如何获取分层文档的子条目总和?

时间:2014-06-22 14:29:48

标签: mongodb mapreduce mongodb-query aggregation-framework

我有一份以下形式的文件:

{
    "name": "root1",
    "children": [{
        "name": "A",
        "children": [{
            "name": "A1",
            "items": 20
        }, {
            "name": "A2",
            "items": 19
        }],
        "items": 8
    }, {
        "name": "B",
        "items": 12
    }],
    "items": 1
}

也就是说,每个级别都有一个“名称”字段,一个“项目”字段,以及一个子字段。我想运行一个查询,它返回每个根的项目总数。在这个例子中,它应该返回(因为20 + 19 + 8 + 12 + 1 = 60)

{ "_id" : "root1", "items" : 60 }

但是,每个文档可以有任意多个级别。也就是说,此示例在根目录下方有两到三个子项,但其他文档可能有更多。也就是说,我不能做像

这样的事情
db.myCollection.aggregate( { $unwind : "$children" },
    { $group : { _id : "$name", items: { $sum : "$items" } } } )

哪种查询有效?

1 个答案:

答案 0 :(得分:0)

使用聚合框架确实无法将数组下降到任意深度。对于这种结构,您需要使用mapReduce,您可以以编程方式执行此操作:

db.collection.mapReduce(
    function () {

        var items = 0;

        var action = function(current) {
            items += current.items;
            if ( current.hasOwnProperty("children") ) {
                current.children.forEach(function(child) {
                    action( child );
              });
            }
        };

        action( this );
        emit( this.name, items );

    },
    function(){},
    { "out": { "inline": 1 } }
)

如果您不想使用mapReduce,那么请考虑另一种数据结构,并采用不同的方式:

{ "name": "root1", "items": 1, "path": [], "root": null },
{ "name": "A", "items": 8,  "path": ["root1"], "root": "root1" },
{ "name": "A1", "items": 20, "path": ["root1", "A"], "root": "root1" },
{ "name": "A2", "items": 19, "path": ["root1", "A"], "root": "root1" },
{ "name": "B", "items": 12, "path": ["root1"], "root": "root1" }

然后你只有一个简单的聚合:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$cond": [
                "$root",
                "$root",
                "$name"
            ]
        },
        "items": { "$sum": "$items" }
    }}
])

因此,如果您采用不同的方法来映射层次结构,那么在没有原本需要的递归检查的情况下执行诸如聚合路径总计之类的事情要容易得多。

您需要的方法取决于您的实际使用要求。