mongodb检查数组中的所有子文档是否在一个字段中具有相同的值

时间:2016-02-29 08:20:52

标签: mongodb mongodb-query aggregation-framework

我有一个文档集合,每个文档都有一个子文档数组的字段,所有子文档都有一个公共字段'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"
                }
        ]
}

我想检查所有的妻子是否已经死亡,只找到比尔。

2 个答案:

答案 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 }

如果您需要查找具有相同状态的用户的记录,则可以删除初始匹配阶段。