ArangoDB AQL:更新内嵌数组中的单一对象

hof1towb  于 2022-12-09  发布在  Go
关注(0)|答案(2)|浏览(135)

我正在尝试使用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

谢谢你的帮助。
此致,Anjan

vnzz0bqm

vnzz0bqm1#

要做到这一点,我们必须使用临时变量。我们将收集其中的子列表并对其进行修改。我们选择一个简单的布尔过滤条件,以使查询更容易理解。
首先,让我们创建一个包含示例的集合:

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

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

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
yh2wf1be

yh2wf1be2#

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']});

相关问题