MongoDB(mongoose)聚合集合中特定ObjectID的计数实例

kbj*_*bjr 3 javascript mongoose mongodb node.js aggregation-framework

假设我的模式看起来像这样:

{
    field: [{
        subDoc: ObjectId,
        ...
    }],
    ...
}
Run Code Online (Sandbox Code Playgroud)

我有一些ObjectIds(用户输入)列表,我如何得到这些特定ObjectIds的计数?例如,如果我有这样的数据:

[
    {field: [ {subDoc: 123}, {subDoc: 234} ]},
    {field: [ {subDoc: 234}, {subDoc: 345} ]},
    {field: [ {subDoc: 123}, {subDoc: 345}, {subDoc: 456} ]}
]
Run Code Online (Sandbox Code Playgroud)

并且用户给出的id列表是123, 234, 345,我需要计算给定的id,所以结果近似于:

{
    123: 2,
    234: 2,
    345: 2
}
Run Code Online (Sandbox Code Playgroud)

最好的方法是什么?

Nei*_*unn 5

聚合框架本身如果不按照你提出的输出方式动态命名键,那真的是一件好事.但你可以像这样做一个查询:

db.collection.aggregate([
    // Match documents that contain the elements
    { "$match": { 
        "field.subDoc": { "$in": [123,234,345] }
    }},

    // De-normalize the array field content
    { "$unwind": "$field" },

    // Match just the elements you want
    { "$match": { 
        "field.subDoc": { "$in": [123,234,345] }
    }},

    // Count by the element as a key
    { "$group": {
        "_id": "$field.subDoc",
        "count": { "$sum": 1 }
    }}
])
Run Code Online (Sandbox Code Playgroud)

这给你输出如下:

{ "_id" : 345, "count" : 2 }
{ "_id" : 234, "count" : 2 }
{ "_id" : 123, "count" : 2 }
Run Code Online (Sandbox Code Playgroud)

但是,如果您真的想要坚持这一点,那么您在查询中指定了所需的"键",因此您可以形成如下管道:

db.collection.aggregate([
    { "$match": { 
        "field.subDoc": { "$in": [123,234,345] }
    }},
    { "$unwind": "$field" },
    { "$match": { 
        "field.subDoc": { "$in": [123,234,345] }
    }},
    { "$group": {
        "_id": "$field.subDoc",
        "count": { "$sum": 1 }
    }},
    { "$group": {
        "_id": null,
        "123": { 
            "$max": {
                "$cond": [
                    { "$eq": [ "$_id", 123 ] },
                    "$count",
                    0
                ]
            }
        },
        "234": { 
            "$max": {
                "$cond": [
                    { "$eq": [ "$_id", 234 ] },
                    "$count",
                    0
                ]
            }
        },
        "345": { 
            "$max": {
                "$cond": [
                    { "$eq": [ "$_id", 345 ] },
                    "$count",
                    0
                ]
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

通过处理参数列表,在代码中构造最后一个阶段是一件相对简单的事情:

var list = [123,234,345];

var group2 = { "$group": { "_id": null } };

list.forEach(function(id) {
    group2["$group"][id] = { 
        "$max": {
            "$cond": [
                { "$eq": [ "$_id", id ] },
                "$count",
                0
            ]
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

而这或多或少都是你想要的.

{ 
    "_id" : null, 
    "123" : 2, 
    "234" : 2, 
    "345" : 2 
}
Run Code Online (Sandbox Code Playgroud)