11

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?

User:

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

AQL Attempt so far

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

Thank you for the help.

Regards, Anjan

2 Answers 2

14

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
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @dothebart! This is great! I knew that the entire sublist might have to be passed in the update/merge but was struggling with setting up that sublist. Thanks again.
9

ArangoDB now supports subset indexes. The following query is based on dothebarts answer:

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

Note: Don't forget to create a hash index on subList[*].filterByMe:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.