使用MongoDB 4.2及更高版本,更新方法现在可以接受一个文档或
聚合管道,其中可以使用以下阶段:
$addFields
和它的别名 $set
$project
和它的别名 $unset
$replaceRoot
和它的别名 $replaceWith
。
掌握了上述内容,您使用聚合管道进行更新操作时,将通过连接筛选后的 tags
数组和映射数组来覆盖 tags
字段,并在映射中查找一些数据:
首先,过滤tags数组的聚合表达式使用了
$filter
并且如下所示:
const myTags = ["architecture", "blabladontexist"];
{
"$filter": {
"input": "$tags",
"cond": {
"$not": [
{ "$in": ["$$this.t", myTags] }
]
}
}
}
它会生成过滤后的文档数组。
[
{ "t" : "contemporary", "n" : 2 },
{ "t" : "creative", "n" : 1 },
{ "t" : "concrete", "n" : 3 }
]
现在的第二部分是派生出另一个数组,该数组将与上述数组连接。这个数组需要对输入数组
myTags
进行
$map
处理:
{
"$map": {
"input": myTags,
"in": {
"$cond": {
"if": { "$in": ["$$this", "$tags.t"] },
"then": {
"t": "$$this",
"n": {
"$sum": [
{
"$arrayElemAt": [
"$tags.n",
{ "$indexOfArray": [ "$tags.t", "$$this" ] }
]
},
1
]
}
},
"else": { "t": "$$this", "n": 0 }
}
}
}
}
上述代码中的
$map
本质上是循环遍历输入数组,并检查每个元素是否在
tags
数组中,比较
t
属性,如果存在,则子文档的
n
字段的值变为其当前的
n
值。
{
"$arrayElemAt": [
"$tags.n",
{ "$indexOfArray": [ "$tags.t", "$$this" ] }
]
}
否则添加默认文档,n值为0。
总体而言,您的更新操作如下:
您的最终更新操作如下:
const myTags = ["architecture", "blabladontexist"];
db.getCollection('coll').update(
{ "_id": "1234" },
[
{ "$set": {
"tags": {
"$concatArrays": [
{ "$filter": {
"input": "$tags",
"cond": { "$not": [ { "$in": ["$$this.t", myTags] } ] }
} },
{ "$map": {
"input": myTags,
"in": {
"$cond": [
{ "$in": ["$$this", "$tags.t"] },
{ "t": "$$this", "n": {
"$sum": [
{ "$arrayElemAt": [
"$tags.n",
{ "$indexOfArray": [ "$tags.t", "$$this" ] }
] },
1
]
} },
{ "t": "$$this", "n": 0 }
]
}
} }
]
}
} }
],
{ "upsert": true }
);
tags
数组中引用Tag
实体的ID。 - Josh Beam