我有一个文档集合,每个文档都有一个子文档数组的字段,所有子文档都有一个公共字段'status'。我想找到所有子文档具有相同状态的所有文档。
系列:
{
"name" : "John",
"wives" : [
{
"name" : "Mary",
"status" : "dead"
},
{
"name" : "Anne",
"status" : "alive"
}
]
},
{
"name" : "Bill",
"wives" : [
{
"name" : "Mary",
"status" : "dead"
},
{
"name" : "Anne",
"status" : "dead"
}
]
},
{
"name" : "Mohammed",
"wives" : [
{
"name" : "Jane",
"status" : "dead"
},
{
"name" : "Sarah",
"status" : "dying"
}
]
}
我想检查所有的妻子是否已经死亡,只找到比尔。
答案 0 :(得分:2)
处理此问题的最有效方法始终是将“dead”状态“匹配”为开放查询,否则您正在处理无法匹配的项目,并且逻辑真的非常简单地跟随{ {3}}和$map
:
db.collection.aggregate([
{ "$match": { "wives.status": "dead" } },
{ "$redact": {
"$cond": {
"if": {
"$allElementsTrue": {
"$map": {
"input": "$wives",
"as": "wife",
"in": { "$eq": [ "$$wife.status", "dead" ] }
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
与$allElementsTrue
相同:
db.collection.find({
"wives.status": "dead",
"$where": function() {
return this.wives.length
== this.wives.filter(function(el) {
el.status == "dead";
}).length;
}
})
两者都基本上测试所有元素的“状态”值,以确保它们以最快的方式匹配。但只有$where
和$match
的汇总管道应该更快。而“较少”的管道阶段(基本上每个都通过数据)也意味着更快。
当然,在文档上保留属性总是最快的,但它只涉及逻辑来设置只有“所有元素”属于同一属性的地方。当然,这通常意味着在每次更新之前通过从服务器加载来检查文档。
答案 1 :(得分:1)
您可以使用以下聚合查询来获取妻子全部死亡的人的记录:
db.collection.aggregate(
{$project: {name:1, wives:1, size:{$size:'$wives'}}},
{$unwind:'$wives'},
{$match:{'wives.status':'dead'}},
{$group:{_id:'$_id',name:{$first:'$name'}, wives:{$push: '$wives'},size:{$first:'$size'},count:{$sum:1}}},
{$project:{_id:1, wives:1, name:1, cmp_value:{$cmp:['$size','$count']}}},
{$match:{cmp_value:0}}
)
<强>输出:强>
{ "_id" : ObjectId("56d401de8b953f35aa92bfb8"), "name" : "Bill", "wives" : [ { "name" : "Mary", "status" : "dead" }, { "name" : "Anne", "status" : "dead" } ], "cmp_value" : 0 }
如果您需要查找具有相同状态的用户的记录,则可以删除初始匹配阶段。