MongoDB:根据文档中的另一个属性从数组中选择元素

时间:2017-01-19 14:39:50

标签: mongodb mongodb-query aggregation-framework

我有一个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

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

1 个答案:

答案 0 :(得分:2)

使用聚合框架:

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;
})