ebb*_* mo 5 javascript mongoose mongodb
我搜索了SO并抓取了Mongoose/Mongo文档,但无济于事,因此我的问题.
我想$inc在嵌套数组中的对象中的值,或者$setOnInsert如果它还没有,则创建该对象.
我看到的Mongo文件如下:
{
"_id": "123",
"members": [
{
"first": "johnny",
"last": "knoxville",
"score": 2
},
{
"first": "johnny",
"last": "cash",
"score": 3
},
// ...and so on
],
}
Run Code Online (Sandbox Code Playgroud)
根据这个例子,我的用例是:
count如果数组对象中存在变量(基于first和找到last),则递增该变量score尚不存在,则将对象添加为1从这篇文章中我了解到我不能同时$set拥有一个我想要的变量$inc.好的 - 这很有道理.
这篇文章有助于理解位置$运算符,以便找到嵌套对象并增加它.
如果我知道该文档存在,我可以简单地进行如下更新:
myDoc = { first: 'johnny', last: 'cash' };
myCollection.findOneAndUpdate(
{
_id: '123',
'members.first': 'johnny',
'members.last': 'cash'
},
{
$inc: { "members.$.score": 1 }
}
);
Run Code Online (Sandbox Code Playgroud)
但是如果我想插入成员(score: 1如果它还不存在)怎么办?
我的问题是,当我使用upsert:true时,位置运算符会抛出错误,因为它可能不会与upsert一起使用(请参阅官方文档).
我尝试了各种组合,并希望避免2 db访问(读/写).
有没有办法在一次操作中执行此操作?
在 MongoDB 4.2 及更高版本中,更新方法现在可以采用文档或聚合管道,其中可以使用以下阶段:
$addFields及其别名$set$project及其别名$unset$replaceRoot及其别名$replaceWith。有了上述内容,您对聚合管道的更新操作将是根据条件覆盖成员字段,即模板如下:
var myDoc = { first: 'johnny', last: 'cash', score: 1 };
db.getCollection('myCollection').update(
{ "_id" : "123" },
[
"$set": {
"members": {
"$cond": {
"if": {}, // does the members array contain myDoc?
"then": {}, // map the members array and increment the score
"else": {} // add myDoc to the existing members array
}
}
}
]
);
Run Code Online (Sandbox Code Playgroud)
要获取第一个条件的表达式,成员数组是否包含 myDoc?,您需要一种$filter基于满足第一个和最后一个属性具有相同值的条件的数组方法myDoc,即
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
}
Run Code Online (Sandbox Code Playgroud)
检查结果数组的第一个元素$arrayElemAt
{
"$arrayElemAt": [
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
},
0
]
}
Run Code Online (Sandbox Code Playgroud)
如果没有匹配,那么上面的内容将为 null,我们可以用一个可以用作主要条件的值来替换 null $ifNull:
{
"$ifNull": [
{
"$arrayElemAt": [
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
},
0
]
},
0
]
}
Run Code Online (Sandbox Code Playgroud)
以上成为我们用于$ne检查不等式的第一个 IF 语句的条件的基础:
{ "$ne": [
{
"$ifNull": [
{
"$arrayElemAt": [
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
},
0
]
},
0
]
},
0
] }
Run Code Online (Sandbox Code Playgroud)
如果上述条件成立,则$map表达式变为
{
"$map": {
"input": "$members",
"in": {
"$cond": [
{ "$eq": [{ "$ifNull": ["$$this.score", 0 ] }, 0] },
{ "$mergeObjects": ["$$this", { "score": 1 } ] },
{ "$mergeObjects": ["$$this", { "score": { "$sum": ["$$this.score", 1] } } ] }
]
}
}
}
Run Code Online (Sandbox Code Playgroud)
否则将新文档添加到现有成员数组中$concatArrays
{
"$concatArrays": [
{ "$ifNull": ["$members", []] },
[ myDoc ]
]
}
Run Code Online (Sandbox Code Playgroud)
您的最终更新操作变为:
var myDoc = { first: 'johnny', last: 'cash', score: 1 };
db.getCollection("myCollection").update(
{ "_id" : "123" },
[
{ "$set": {
"members": {
"$cond": {
"if": {
"$ne": [
{
"$ifNull": [
{
"$arrayElemAt": [
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
},
0
]
},
0
]
},
0
]
},
"then": {
"$map": {
"input": "$members",
"in": {
"$cond": [
{ "$eq": [{ "$ifNull": ["$$this.score", 0 ] }, 0] },
{ "$mergeObjects": ["$$this", { "score": 1 } ] },
{ "$mergeObjects": ["$$this", { "score": { "$sum": ["$$this.score", 1] } } ] }
]
}
}
},
"else": {
"$concatArrays": [
{ "$ifNull": ["$members", []] },
[ myDoc ]
]
}
}
}
} }
],
{ "upsert": true }
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |