如何使用主文档中的值查询子文档数组

时间:2015-01-19 01:51:50

标签: mongodb mongodb-query aggregation-framework

我有一个具有一些属性的文档,其中一个属性是子文档数组,我想查找文档并将主文档中的属性与子文档数组中的属性进行比较

以下是文档的示例

{
"_id" : ObjectId("54bb897d52a8a302ecafeb03"),
“Contract" : “ABCDE",
“OptimalYear" : 2012,
"Results" : [ 

    {
        "Year" : 2011,
        "Risk" : 1114
    }, 
    {
        "Year" : 2012,
        "Risk" : 1226
    }, 
    {
        "Year" : 2013,
        "Risk" : 1385.5
    }
]
}

我能做到

db.CC.find({
Contract: "Jan",
Result: {
    $elemMatch: {
        Year: 2012
    }
}
})

但是如何在$ elemMatch中使用OptimalYear的值{Year:OptimalYear}

1 个答案:

答案 0 :(得分:1)

您不能使用标准查询执行此操作,或者大多数人实际要求的是在处理更新时引用文档中字段的值。没有语法允许在这些查询中引用字段值。

您可以使用聚合框架执行此操作。自MongoDB 2.6以来的现代版本具有$redact管道阶段,它有一个很好的处理方式:

db.collection.aggregate([
    { "$redact": {
        "$cond": {
            "if": {
                "$eq": [
                    { "$ifNull": [ "$Year", "$$ROOT.OptimalYear" ] },
                    "$$ROOT.OptimalYear"
                ]
            },
            "then": "$$DESCEND",
            "else": "$$PRUNE"
        }
    }}
])

这基本上会评估$cond条件或三元语句,以查看值实际匹配的位置,然后保留元素。否则,将删除当前文档级别。

$ifNull$$ROOT的引用一起存在,因为这是通过结构的递归。例如,文档顶部没有“Year”字段,因此比较将替换为“OptimalYear”值。与你自己比较会返回true,但是在数组中它会与存在的“Year”进行比较。

在早期版本中,仍然可以这样做,但它确实需要更多工作,因此不是最佳方式:

db.collection.aggregate([
    { "$unwind": "$Results" },
    { "$project": {
        "Contract": 1,
        "OptimalYear": 1,
        "Results": 1,
        "matched": { "$eq": [ "$Results.Year", "$OptimalYear" ] }
    }},
    { "$match": { "matched": true } },
    { "$group": {
        "_id": "$_id",
        "Contract": { "$first": "$Contract" },
        "OptimalYear": { "$first": "$OptimalYear" },
        "Results": { "$push": "$Results" }
    }}
])

不完全相同,因为它过滤掉了没有完全匹配的文档,您也可以在之前的版本中添加额外的$match阶段检查空数组。