我想使用貓鼬查詢從嵌套物件陣列中檢索確切的物件。我嘗試了一些使用 $elemMatch 的查詢,但沒有得到我要定位的確切物件,而是我得到了物件陣列。
我的 BSON 是
{
"_id": {
"$oid": "622bcb7a1091ddd45201258e"
},
"type": "Humans",
"person": [
{
"name": "Name Person 1",
"visited": [],
"_id": {
"$oid": "622bdjnmyi30e62d6d166ebd"
}
},
{
"name": "Name Person 2",
"visited": [
{
"country": "Country 1",
"year": "2022",
"id": "zuPks8cv3n"
}
],
"_id": {
"$oid": "622bdopmLks0e62d6d166ebe"
}
},
{
"name": "Name Person 3",
"_id": {
"$oid": "622bdpo8bnj0e62d6d166ebf"
},
"visited": [
{
"country": "Country 3",
"year": "2029",
"id": "l2Opx489xb"
},
{
"country": "Country 4",
"year": "2002",
"id": "s09zbHYjIp"
}
]
},
{
"name": "Name Person 4",
"visited": [],
"_id": {
"$oid": "622bdb9eio0sbt2d6d166ec0"
}
}
],
"__v": {
"$numberInt": "0"
}
}
我的目標是“Name Person 3” ,其中包含“visited”物件陣列和 id 為“l2Opx489xb”的物件。
我的預期結果是:
{
"country": "Country 3",
"year": "2029",
"id": "l2Opx489xb"
}
uj5u.com熱心網友回復:
這是常見問題的一種變體,其中嘗試匹配陣列中的單個專案會產生整個陣列。問題不在于“匹配”,因為匹配是正確的;這是一個投影問題。找到匹配項后,我們只希望投影陣列中的特定專案或檔案的其余部分。
這是一個具有單個階段且沒有$unwind. 通常,在、和之間$filter,可以從沒有 的單個檔案中提取資料,這可能會很昂貴。從 #1 開始閱讀“由內而外”的評論。$map$reduce$unwind
db.foo.aggregate([
{$replaceRoot: {newRoot: // #7 ...and make this the root object
{$first: // #6 like #2, turn the array of 1 into a single object.
{$filter: { // #4 ... and now we filter the 'visited' array...
input: {$let: {
vars: {qq: {$first: // #2 $filter will yield an array of 0 or 1;
// use $first to turn into one object
// #1 Find Name Person 3
{$filter: {
input: '$person',
cond: {$eq:['$$this.name','Name Person 3']}
}}
}},
// #3 We wish we could say $first.visited in #2 but we cannot
// so we use $let and the vars setup to allow us to get to
// the inner array 'visited':
in: '$$qq.visited'}
},
cond: {$eq:['$$this.id','l2Opx489xb']} // #5 to match target id
}}
}
}}
]);
{ "country" : "Country 3", "year" : "2029", "id" : "l2Opx489xb" }
注意: $first到達 v4.4。對于早期版本,而不是
{$first: <expression that yields array>}
改用這個:
{$arrayElemAt: [ <expression that yields array>, 0]
$first,0更簡潔一些,因為在復雜運算式的末尾沒有“懸空”。
下面是“擴展”版本加上一個額外的檢查$X評估到null(如果Name Person 3或目標 id 不存在),因為null不能傳遞給$replaceRoot:
db.foo.aggregate([
{$project: {
X: {$first: {$filter: {
input: '$person',
cond: {$eq:['$$this.name','Name Person 3']}
}} }
}}
,{$project: {
X: {$first: {$filter: {
input: '$X.visited',
cond: {$eq:['$$this.id','l2Opx489xb']}
}} }
}}
,{$match: {X: {$ne: null}} }
,{$replaceRoot: {newRoot: '$X'}}
]);
OP 已將問題擴展為包括 1. 洗掉visited陣列中的專案 2. 將對等欄位更新為陣列中的 id 匹配項visited。有兩種方法:簡單和“藝術”,探索管道功能的一些力量。
簡單
更新年份和國家:
db.foo.update(
{'person.name':'Name Person 3'}
,{$set: {
'person.$[p].visited.$[v].year':'1999',
'person.$[p].visited.$[v].country':'ZOOP'
}}
,{arrayFilters: [ {'p.name':'Name Person 3'},{'v.id':'l2Opx489xb'} ] }
);
要從visited陣列中完全洗掉目標 id 物件:
db.foo.update(
{'person.name':'Name Person 3'}
,{$pull: {'person.$.visited': {'id':'l2Opx489xb'}}}
);
ARTSY
rc=db.foo.update(
// Use dot notation for match to cut down initial input set.
// Remember: This will NOT find the exact offset into the
// array where Name Person 3 may be found, only that it is
// *somewhere* in that array. But this is good to filter out
// things where NO update is needed. The pipeline below will
// hunt for and remove the target id.
{'person.name':'Name Person 3'},
[{$set: { // pipeline form of update
// Use $reduce to walk the person array and essentially
// rebuild it but only operating on those entries where
// name is 'Name Person 3'
person: {$reduce: {
input: '$person',
initialValue: [],
// $concatArrays wants 2 arrays. The first is our ever-growing
// $$value. The second is a candidate object -- but we have to
// turn THAT into an array of 1, so watch for the [ ] wrapper around
// the outer $cond expression.
in:{$concatArrays: [ "$$value", [
{$cond: [
{$ne:['$$this.name','Name Person 3']}, // if NOT our target
'$$this', // THEN pass to concatArrays unchanged (noop)
// ELSE
// To DELETE the entire object:
// overwrite 'visited' with filtered version
// of same. This lets all other vars like name
// and anything else pass thru unchanged.
{$mergeObjects: [ '$$this',
{visited: {$filter: {
input: '$$this.visited',
as: 'qq',
cond: {$ne:['$$qq.id','l2Opx489xb']}
}}
}
]}
/*
To UPDATE year and country in the target, use
this instead instead of the $mergeObjects call
just above. Choose one or the other; both cannot
be active at same time.
{$mergeObjects: [ '$$this',
{visited: {$map: { // $map this time, not $filter
input: '$$this.visited',
as: 'qq',
in: {$cond:[
{$ne:['$$qq.id','l2Opx489xb']},
'$$qq', // THEN return unchanged
// ELSE overwrite year and country
// fields of the object:
{$mergeObjects: [ '$$qq',
{year:"1999",
country:"ZPONC"}
]}
]}
}}
}
]}
*/
]}
]] }
}}
}}
]
// ,{multi:true} // if Name Person 3 exists in more than 1 doc....
);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/443293.html
