【问题标题】:MongoDB: Select element from array based on another property in the documentMongoDB:根据文档中的另一个属性从数组中选择元素
【发布时间】:2017-01-19 14:39:50
【问题描述】:

我有一个 MongoDB 集合,其中包含以下结构的文档(不感兴趣的部分省略了):

{
  displayFieldId: "abcd",
  fields: [
    {
      fieldId: "efgh",
      value: "cake"
    },
    {
      fieldId: "abcd",
      value: "cheese"
    },
    ....
  ],
  ....
}

我想对此集合运行查询以仅获取fields 数组中fieldId 与文档的displayFieldId 匹配的元素。因此,对上述文档的查询结果应该是:

{
  fields: [
    {
      fieldId: "abcd",
      value: "cheese"
    }
  ],
  ....
}

我构造了以下查询。它可以满足我的要求,但 displayFieldValue 是硬编码的

db.containers.find({}, {
  fields: {
    $elemMatch: {
      fieldId: "abcd"
    }
  }
});

有没有办法让它查看文档的displayFieldId 并使用该值而不是硬编码的"abcd"


服务器正在运行 MongoDB 3.2.6

如果可能的话,我想在没有聚合的情况下这样做,但如果不能这样做,那么聚合将不得不这样做

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    使用聚合框架:

    db.containers.aggregate([
        {        
            "$redact": { 
                "$cond": [
                    { 
                        "$anyElementTrue": [ 
                            {
                                "$map": {
                                    "input": "$fields",
                                    "as": "el",
                                    "in": { 
                                        "$eq": ["$$el.fieldId", "$displayFieldId"]
                                    }
                                }
                            }
                        ] 
                    },
                    "$$KEEP",
                    "$$PRUNE"
                ]
            }
        },
        {
            "$project": {
                "displayFieldId": 1,
                "fields": {
                    "$filter": {
                        "input": "$fields",
                        "as": "el",
                        "cond": {
                            "$eq": ["$$el.fieldId", "$displayFieldId"]
                        }
                    }
                },
                "otherfields": 1,
                ....
            }
        }
    ])
    

    MongoDB 3.4

    db.containers.aggregate([
        {        
            "$redact": { 
                "$cond": [
                    { 
                        "$anyElementTrue": [ 
                            {
                                "$map": {
                                    "input": "$fields",
                                    "as": "el",
                                    "in": { 
                                        "$eq": ["$$el.fieldId", "$displayFieldId"]
                                    }
                                }
                            }
                        ] 
                    },
                    "$$KEEP",
                    "$$PRUNE"
                ]
            }
        },
        {
            "$addFields": {
                "fields": {
                    "$filter": {
                        "input": "$fields",
                        "as": "el",
                        "cond": {
                            "$eq": ["$$el.fieldId", "$displayFieldId"]
                        }
                    }
                }
            }
        }
    ])
    

    没有聚合框架 - 使用 $where(慢查询):

    db.containers.find({
        "$where": function() {
            var self = this;
            return this.fields.filter(function(f){
                return self.displayFieldId === f.fieldId;
            }).length > 0;
        }
    }).map(function(doc){
        var obj = doc;
        obj.fields = obj.fields.filter(function(f){
            return obj.displayFieldId === f.fieldId;
        });
        return obj;
    })
    

    【讨论】:

    • 如何将缓慢的查询向下移动
    • 我注意到我忘了提到我想返回所有文档,而不是过滤掉那些没有显示字段的文档。没有它的人应该返回一个空的fields 数组。我设法通过删除聚合查询的$redact 部分和查找查询的$where 部分来做到这一点。虽然,至少在 find 查询中,这与返回整个数据库并在客户端处理它没有什么不同,不是吗?看来我必须采取另一种方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多