Mongo: 获取聚合的hashmap

Mongo: get hashmap in aggregate

我有collectiondb.problems。每个文档包含嵌套的 areacategory objects。文档示例:

{
    _id: 1,
    text: 'Hello',
    area: {_id: 23, title: 'Area 61'},
    category: {_id: 12, title: 'Just a category'}
}

我正在尝试按类别统计每个领域的问题并得到如下结果:

[
    {
        area: {_id: 2, title: 'Area 61'},
        categoriesStats: {
            12: {title: 'Just a category', problemCount: 123},
            42: {title: 'Another category', problemCount: 11}
        }
   },
   {...}
]

主要是categoriesStats必须是一个散列(以类别的id为键)

我现在想到的是:

db.problems.aggregate([
    {$group: {
        _id: {areaId: '$area._id', categoryId: '$category._id'},
        problemCount: {$sum: 1},
        area: {$first: '$area'},
        category: {$first: '$category'}
    }},
    {$group: {
        _id: '$_id.areaId',
        area: {$first: '$area'},
        categoriesStats: {
            $push: {
                problemCount: '$problemCount',
                category: '$category'
            }
        }
    }},
    {$project: {_id: 0, area: 1, categoriesStats: 1}}
])

本次查询的结果:

{
    "result": [ 
        {
            "area": {"_id": 37, "name": "Some area"},
            "categoriesStats": [
                {
                    "problemCount": 1,
                    "category": {"_id": 4, "title": "Just a cat"}
                },
                {
                    "problemCount": 1,
                    "category": {"_id": 3, "title": "Misc"}
               }
            ]
        }, 
        {
            "area": {"_id": 36, "name": "wow such area"},
            "categoriesStats": [ 
                {
                    "problemCount": 1,
                    "category": {"_id": 4, "title": "Just a cat"}
                }, 
                {
                    "problemCount": 2,
                    "category": {"_id": 3, "title": "Misc"}
                }
            ]
        }
    ],
    "ok": 1
}

如您所见,我已经设法获得几乎需要的结果,但我无法获得 categoriesStats 作为哈希值。

我在 $project 阶段尝试过查询,例如 {$project: {'$category._id': '$categories'},但是

"$expressions are not allowed at the top-level of $project"

我也试过像这样预定义查询:

3 是某个类别的 _id

{$group: ...},
{$project: {
 'categoriesStats.3': {$cond: [{$eq: ['$category._id', 3]}, '$category', null]}}, 
 //Same field for every category _id
{$group: ...}

但在这种情况下,我无法通过 $group 阶段

获取此哈希

所以,问题是,有没有办法以 hashmap 形式得到 categoriesStats

可以修改聚合结果,使用游标方法forEach()迭代游标访问文档,如下例:

var cur = db.problems.aggregate([
    {$group: {
        _id: {areaId: '$area._id', categoryId: '$category._id'},
        problemCount: {$sum: 1},
        area: {$first: '$area'},
        category: {$first: '$category'}
    }},
    {$group: {
        _id: '$_id.areaId',
        area: {$first: '$area'},
        categoriesStats: {
            $push: {
                problemCount: '$problemCount',
                category: '$category'
            }
        }
    }},
    {$project: {_id: 0, area: 1, categoriesStats: 1}}
]),
results = [];

cur.forEach(function (res){
    var obj = { 
        "categoriesStats": {} 
    };
    var category = {};
    obj.area = res.area;
    res.categoriesStats.forEach(function(c){
        var cat = {};        
        cat["title"] = c.category.title;
        cat["problemCount"] = c.problemCount;        
        obj["categoriesStats"][c.category._id.toString()] = cat;
    });

    results.push(obj);
});

查看下面的演示

var cur = {
    "result": [ 
        {
            "area": {"_id": 37, "name": "Some area"},
            "categoriesStats": [
                {
                    "problemCount": 1,
                    "category": {"_id": 4, "title": "Just a cat"}
                },
                {
                    "problemCount": 1,
                    "category": {"_id": 3, "title": "Misc"}
               }
            ]
        }, 
        {
            "area": {"_id": 36, "name": "wow such area"},
            "categoriesStats": [ 
                {
                    "problemCount": 1,
                    "category": {"_id": 4, "title": "Just a cat"}
                }, 
                {
                    "problemCount": 2,
                    "category": {"_id": 3, "title": "Misc"}
                }
            ]
        }
    ],
    "ok": 1
};
var results = [];
cur.result.forEach(function (doc){
    var obj = { 
        "categoriesStats": {} 
    };
    var category = {};
    obj.area = doc.area;
    doc.categoriesStats.forEach(function(c){
        var cat = {};        
        cat["title"] = c.category.title;
        cat["problemCount"] = c.problemCount;        
        obj["categoriesStats"][c.category._id.toString()] = cat;
    });
    
    results.push(obj);
});

pre.innerHTML = JSON.stringify(results);
<pre id="pre"></pre>