![](/img/trans.png)
[英]Accessing nested object in nested array using a variable (MongoDB, Node, Inc)
[英]MongoDB $inc and $setOnInsert for nested array
我已經搜索了SO,並檢索了Mongoose / Mongo文檔,但無濟於事,因此是我的問題。
我想在嵌套數組中的對象中增加$inc
的值,或者創建$setOnInsert
此對象(如果尚不存在)。
我擁有的Mongo文件如下:
{
"_id": "123",
"members": [
{
"first": "johnny",
"last": "knoxville",
"score": 2
},
{
"first": "johnny",
"last": "cash",
"score": 3
},
// ...and so on
],
}
根據此示例,我的用例是:
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 }
}
);
但是,如果我還想插入該成員( score: 1
),該怎么辦呢?
我的問題是,當我使用upsert:true時,位置運算符會引發錯誤,因為它可能無法與upsert一起使用(請參閱官方文檔 )。
我嘗試了各種組合,並希望避免2個數據庫訪問(讀/寫)。
有沒有一種方法可以做到這一點?
在MongoDB 4.2及更高版本中,更新方法現在可以獲取文檔或聚合管道 ,可以在其中使用以下階段:
$addFields
及其別名$set
$project
及其別名$unset
$replaceRoot
及其別名$replaceWith
。 有了以上內容,您對聚合管道的更新操作將根據條件(即模板如下)覆蓋members字段:
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
}
}
}
]
);
為了獲得第一個條件的表達式, 成員數組是否包含myDoc? ,您需要一種方法,根據滿足與myDoc
分別具有相同值的first和last屬性的條件來對數組進行$filter
,即
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
}
使用$arrayElemAt
檢查結果數組的第一個元素
{
"$arrayElemAt": [
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
},
0
]
}
如果沒有匹配項,則上面的內容將為null,我們可以用可以用作$ifNull
的主要條件的值替換null:
{
"$ifNull": [
{
"$arrayElemAt": [
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
},
0
]
},
0
]
}
以上是我們使用$ne
檢查不等式的第一條IF語句的條件的基礎:
{ "$ne": [
{
"$ifNull": [
{
"$arrayElemAt": [
{
"$filter": {
"input": "$members",
"cond": {
"$and": [
{ "$eq": ["$$this.first", myDoc.first] },
{ "$eq": ["$$this.last", myDoc.last] },
]
}
}
},
0
]
},
0
]
},
0
] }
如果上述條件成立,則$map
表達式變為
{
"$map": {
"input": "$members",
"in": {
"$cond": [
{ "$eq": [{ "$ifNull": ["$$this.score", 0 ] }, 0] },
{ "$mergeObjects": ["$$this", { "score": 1 } ] },
{ "$mergeObjects": ["$$this", { "score": { "$sum": ["$$this.score", 1] } } ] }
]
}
}
}
否則使用$concatArrays
將新文檔添加到現有成員數組中
{
"$concatArrays": [
{ "$ifNull": ["$members", []] },
[ myDoc ]
]
}
您的最終更新操作將變為:
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 }
);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.