ArangoDB AQL: Update single object in embedded array

前端 未结 2 746
陌清茗
陌清茗 2020-12-10 05:15

I am trying to update the attribute on a json document in an embedded array using AQL. How do i update the \"addressline\" for \"home\" type address using AQL below?

<
2条回答
  •  北海茫月
    2020-12-10 06:06

    To do this we have to work with temporary variables. We will collect the sublist in there and alter it. We choose a simple boolean filter condition to make the query better comprehensible.

    First lets create a collection with a sample:

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

    Heres the Query which keeps the subList on alteredList to update it later:

    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
    

    While the query as it is is now functional:

    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" 
          } 
        ] 
      } 
    ]
    

    This query will probably be soonish a performance bottleneck, since it modifies all documents in the collection regardless whether the values change or not. Therefore we want to only UPDATE the documents if we really change their value. Therefore we employ a second FOR to test whether subList will be altered or not:

    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
    

提交回复
热议问题