对于嵌入式文档的查询,我希望返回匹配元素,以及预先指定的元素集。例如,使用
说我有一个如下的集合:
{_id: 1,
data:[
{who: 'Alice', score: 20},
{who: 'Brad', score: 25},
{who: 'Charlie', score: 30},
{who: 'Dave', score: 40},
{who: 'Elaine', score: 50},
{who: 'Frank', score: 20}
]},
{_id: 2,
data:[
{who: 'Alice', score: 30},
{who: 'Brad', score: 50},
{who: 'Charlie', score: 68},
{who: 'Dave', score: 20},
{who: 'Elaine', score: 50},
{who: 'Frank', score: 20}
]},
...
如果我需要总是返回Alice和Brad,以及得分等于50的任何人,我倾向于使用
find({data.score: 50}, {'data.who': {'$in': ['Alice', 'Brad', '$']}})
or
aggregate([{'$match': {data.score: 50}},
{'$project': {'data': 1}},
{'$unwind': '$data'},
{'$match': {'data.who': {'$in': ['Alice', 'Brad', '$']}}}])
不幸的是,两者都不起作用。
实现它的正确方法是什么,甚至是可能的?
答案 0 :(得分:1)
您可以使用$redact阶段汇总结果。这消除了$unwind阶段的需要,在大数据集的情况下,这可能会被证明是安静的。
代码:
db.t.aggregate([
{$redact:{$cond:[{$or:[{$eq:[{$ifNull:["$who","Alice"]},"Alice"]},
{$eq:[{$ifNull:["$who","Brad"]},"Brad"]},
{$eq:[{$ifNull:["$score",50]},50]}
]},"$$DESCEND","$$PRUNE"]}}
])
或者您可以对现有代码稍作修改,如下所示:
$match
条件应包含所有三个条件
保留一份子文件。
然后$unwind
。
然后再次应用相同的$match
条件以选择未缠绕的条件
文档。
$group
_id
合并所选的数据子文档
每个_id
。
代码:
db.t.aggregate([
{$match:{$or:[{"data.who":{$in:["Alice","Brad"]}},
{"data.score":{$eq:50}}]}},
{$unwind:"$data"},
{$match:{$or:[{"data.who":{$in:["Alice","Brad"]}},
{"data.score":{$eq:50}}]}},
{$group:{"_id":"$_id","data":{$push:"$data"}}}
])
O / P:
{
"_id" : 1,
"data" : [
{
"who" : "Alice",
"score" : 20
},
{
"who" : "Brad",
"score" : 25
},
{
"who" : "Elaine",
"score" : 50
}
]
}
{
"_id" : 2,
"data" : [
{
"who" : "Alice",
"score" : 30
},
{
"who" : "Brad",
"score" : 50
},
{
"who" : "Elaine",
"score" : 50
}
]
}
答案 1 :(得分:0)
我认为根据我的理解,以下查询将符合您的标准
db.collectionName.aggregate({
"$unwind": "$data"
},
{
"$match": {
"$or": [
{
"data.score": 50
},
{
"data.who": "Alice"
},
{
"data.who": "Brad"
}
]
}
},
{
"$project": {
"_id": 0,
"data": "$data"
}
}).pretty()