【问题标题】:mongodb check if all subdocuments in array have the same value in one fieldmongodb检查数组中的所有子文档是否在一个字段中具有相同的值
【发布时间】:2017-07-01 21:49:34
【问题描述】:

我有一个文档集合,每个文档都有一个字段,它是一个子文档数组,所有子文档都有一个公共字段“状态”。我想查找所有子文档具有相同状态的所有文档。

收藏:

{
        "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"
                }
        ]
}

我想检查是否所有妻子都死了,只找到比尔。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案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 }
    

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

    【讨论】:

    • 似乎更容易有一个额外的字段来存储某种标志值(因为我只对状态字段的一个值感兴趣)。不过还是谢谢。
    • 一个额外的标志将导致进一步的更新和发现保持同步的标志
    【解决方案2】:

    处理此问题的最有效方法始终是将“死亡”状态作为开始查询“匹配”,否则您正在处理不可能匹配的项目,并且逻辑实际上非常简单地遵循@ 987654321@和$allElementsTrue

    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"
            }
        }}    
    ])
    

    或与$where 相同:

    db.collection.find({
        "wives.status": "dead",
        "$where": function() {
            return this.wives.length 
                == this.wives.filter(function(el) { 
                    el.status == "dead";
                }).length;
        } 
    })  
    

    两者本质上都是测试所有元素的“状态”值,以确保它们以最快的方式匹配。但是只有$match$redact 的聚合管道应该更快。而“更少”的流水线阶段(基本上每个阶段都通过数据)也意味着更快。

    当然,在文档上保留一个属性总是最快的,但它会涉及逻辑来设置只有“所有元素”都是相同属性的地方。当然,这通常意味着在每次更新之前通过从服务器加载文档来检查文档。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 2012-05-20
      • 1970-01-01
      • 1970-01-01
      • 2013-08-26
      相关资源
      最近更新 更多