为此,我们必须使用临时变量。我们将在那里收集子列表并进行更改。我们选择一个简单的布尔过滤条件来使查询更易于理解。
首先让我们创建一个包含样本的集合:
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"
}
]
}
]
这个查询很快就会成为性能瓶颈,因为它修改集合中的所有文档无论值是否改变。因此,如果我们真的改变了文档的值,我们只想更新文档。因此我们使用第二个 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