MongoDB插入文档“或".增量字段(如果存在于数组中) [英] MongoDB insert document "or" increment field if exists in array
问题描述
我尝试做的事情很简单,我在文档中有一个数组;
"tags": [
{
"t" : "architecture",
"n" : 12
},
{
"t" : "contemporary",
"n" : 2
},
{
"t" : "creative",
"n" : 1
},
{
"t" : "concrete",
"n" : 3
}
]
我想将一组项目推入
这样的数组["architecture","blabladontexist"]
如果项目存在,我想增加对象的n
值(在本例中为architecture
),
,如果没有,则将其添加为新项(值n=0
){ "t": "blabladontexist", "n":0}
我尝试了$addToSet
,$set
,$inc
,$upsert: true
这么多组合,但无法做到.
我们如何在MongoDB中做到这一点?
在MongoDB 4.2和更高版本中,更新方法现在可以获取文档或 $addFields
及其别名 $set
$project
及其别名 $unset
$replaceRoot
及其别名 $replaceWith
.结合上述内容,您使用聚合管道进行的更新操作将通过过滤输入列表的过滤后的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" },
[
{ "$addToSet": {
"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 }
);
What I try to do is fairly simple, I have an array inside a document ;
"tags": [
{
"t" : "architecture",
"n" : 12
},
{
"t" : "contemporary",
"n" : 2
},
{
"t" : "creative",
"n" : 1
},
{
"t" : "concrete",
"n" : 3
}
]
I want to push an array of items to array like
["architecture","blabladontexist"]
If item exists, I want to increment object's n
value (in this case its architecture
),
and if don't, add it as a new Item (with value of n=0
) { "t": "blabladontexist", "n":0}
I have tried $addToSet
, $set
, $inc
, $upsert: true
with so many combinations and couldn't do it.
How can we do this in MongoDB?
With MongoDB 4.2 and newer, the update method can now take a document or an aggregate pipeline where the following stages can be used:
$addFields
and its alias$set
$project
and its alias$unset
$replaceRoot
and its alias$replaceWith
.
Armed with the above, your update operation with the aggregate pipeline will be to override the tags
field by concatenating a filtered tags
array and a mapped array of the input list with some data lookup in the map:
To start with, the aggregate expression that filters the tags array uses the $filter
and it follows:
const myTags = ["architecture", "blabladontexist"];
{
"$filter": {
"input": "$tags",
"cond": {
"$not": [
{ "$in": ["$$this.t", myTags] }
]
}
}
}
which produces the filtered array of documents
[
{ "t" : "contemporary", "n" : 2 },
{ "t" : "creative", "n" : 1 },
{ "t" : "concrete", "n" : 3 }
]
Now the second part will be to derive the other array that will be concatenated to the above. This array requires a $map
over the myTags
input array as
{
"$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 }
}
}
}
}
The above $map
essentially loops over the input array and checks with each element whether it's in the tags
array comparing the t
property, if it exists then the value of the n
field of the subdocument becomes its current n
value
expressed with
{
"$arrayElemAt": [
"$tags.n",
{ "$indexOfArray": [ "$tags.t", "$$this" ] }
]
}
else add the default document with an n value of 0.
Overall, your update operation will be as follows
Your final update operation becomes:
const myTags = ["architecture", "blabladontexist"];
db.getCollection('coll').update(
{ "_id": "1234" },
[
{ "$addToSet": {
"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 }
);
这篇关于MongoDB插入文档“或".增量字段(如果存在于数组中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!