MongoDB聚合包括丢失的文档

时间:2014-07-17 19:36:37

标签: mongodb mongodb-query aggregation-framework

我有一些文档存储在MongoDB中,类似于以下内容:

{
    "id": "0001",
    "name": "Joe",
    "last_name": "Blogs",
    "results":
        [
            { "id": "5001", "mark": "78" },
            { "id": "5002", "mark": "105" },
            { "id": "5005", "mark": "97" },
        ]
}

有许多与上述类似的条目。我遇到的问题是某些“结果”字段完全丢失,因此有些条目如下所示:

{
    "id": "0001",
    "name": "Joe",
    "last_name": "Blogs"
}

我正在尝试聚合它以返回“name”,“last_name”和平均“mark”。我在下面的代码中表现得很好:

db.sites.aggregate( 
 { $project : { name : "$name", last_name : "$last_name", results : "$results" } },
 { $unwind: "$results" },
 { $group : { 
    _id : "$_id", 
    average_mark : { $avg : "$results.mark" }, 
    name : { $last : "$name" },
    last_name : { $last : "$last_name" },
 }
)

但是,它不会返回没有“results”数组的条目。

有没有人知道如何返回丢失的“结果”条目并将平均值设置为零?

干杯,

詹姆斯。

1 个答案:

答案 0 :(得分:5)

当聚合框架遇到“空”数组时,$unwind的结果会有效地从管道中删除文档,因为它被认为没有结果。此外,如果数组根本不存在,则会产生错误,因为操作员将尝试访问不存在的元素。

因此,如果您不希望从汇总结果中明确“过滤”这些文档,则$ifNull运算符就存在。它测试字段的存在,返回该字段或备用提供的参数。

db.sites.aggregate([
    { "$project": { 
        "name": 1, 
        "last_name": 1,
        "results" : { 
            "$ifNull": [ "$results", [{ "mark": 0 }] ]
        }
    }},
    { "$unwind": "$results" },
    { "$group": { 
        "_id" : "$_id", 
        "average_mark": { "$avg": "$results.mark" }, 
        "name": { "$last": "$name" },
        "last_name": { "$last": "$last_name" },
    }}
])

当您真正拥有“空”数组时,使用$cond运算符可以实现类似的结果,甚至可以组合使用:

    "results": { 
        "$cond": [ 
            {"$eq": [ "$results", [] ] },
            [{ "mark": 0 }],
            { "$ifNull": [ "$results", [{ "mark": 0 }] ] }
        ]
    }