ArangoDB AQL:更新嵌入式数组中的单个对象

ArangoDB AQL: Update single object in embedded array

我正在尝试使用 AQL 更新嵌入式数组中 json 文档的属性。我如何使用下面的 AQL 为 "home" 类型地址更新 "addressline"?

用户:

{
name: "test",
address: [
      {"addressline": "1234 superway", type:"home"}, 
      {"addressline": "5678 superway", type:"work"}
     ]
}

到目前为止的 AQL 尝试次数

for u in users
   for a in u.address
     FILTER a.type='home'
       UPDATE u WITH {<What goes here to update addressline?>} in users

感谢您的帮助。

此致, 安然

为此,我们必须使用临时变量。我们将在那里收集子列表并对其进行更改。我们选择一个简单的布尔过滤条件,使查询更好理解。

首先让我们创建一个样本集合:

database = db._create('complexCollection')
database.save({ 
  "topLevelAttribute" : "a", 
  "subList" : [ 
    { 
      "attributeToAlter" : "oldValue", 
      "filterByMe" : true 
    }, 
    { 
      "attributeToAlter" : "moreOldValues", 
      "filterByMe" : true 
    }, 
    { 
      "attributeToAlter" : "unchangedValue", 
      "filterByMe" : false 
    } 
  ] 
})

这是将 subList 保留在 alteredList 上以便稍后更新的查询:

FOR document in complexCollection
  LET alteredList = (
    FOR element IN document.subList 
       LET newItem = (! element.filterByMe ?
                      element :
                      MERGE(element, { attributeToAlter: "shiny New Value" }))
       RETURN newItem)
  UPDATE document WITH { subList:  alteredList } IN complexCollection

虽然查询现在可以正常运行:

db.complexCollection.toArray()
[ 
  { 
    "_id" : "complexCollection/392671569467", 
    "_key" : "392671569467", 
    "_rev" : "392799430203", 
    "topLevelAttribute" : "a", 
    "subList" : [ 
      { 
        "filterByMe" : true, 
        "attributeToAlter" : "shiny New Value" 
      }, 
      { 
        "filterByMe" : true, 
        "attributeToAlter" : "shiny New Value" 
      }, 
      { 
        "filterByMe" : false, 
        "attributeToAlter" : "unchangedValue" 
      } 
    ] 
  } 
]

这个查询可能很快就会成为性能瓶颈,因为它修改集合中的所有文档无论值是否改变 .因此,如果我们真的改变了文档的值,我们只想 UPDATE 文档。因此,我们使用第二个 FOR 来测试 subList 是否会被更改:

FOR document in complexCollection
  LET willUpdateDocument = (
    FOR element IN document.subList 
      FILTER element.filterByMe LIMIT 1 RETURN 1)

  FILTER LENGTH(willUpdateDocument) > 0

  LET alteredList = (
    FOR element IN document.subList 
       LET newItem = (! element.filterByMe ?
                      element :
                      MERGE(element, { attributeToAlter: "shiny New Value" }))
       RETURN newItem)

  UPDATE document WITH { subList:  alteredList } IN complexCollection

ArangoDB 现在支持子集索引。以下查询基于 dothebart 的回答:

FOR document IN complexCollection
    FILTER document.subList[*].filterByMe == true LIMIT 1
    UPDATE document WITH {
        items: (
            FOR element IN document.subList
                RETURN element.filterByMe == true
                     ? MERGE(element, { attributeToAlter: "the shiniest value"})
                     : element
        )
    } IN complexCollection

注意:不要忘记在subList[*].filterByMe上创建一个hash索引:

db._collection('complexCollection')
    .ensureIndex({type:'hash',fields:['subList[*].filterByMe']});