MongoDB (mongoose) concatenates instances of specific ObjectIDs in a collection

Assuming I have a schematic that looks something like this:

{
    field: [{
        subDoc: ObjectId,
        ...
    }],
    ...
}

      

and I have a list of ObjectIds (user input), how would I get the count of these specific ObjectIds? For exmaple, if I have data like this:

[
    {field: [ {subDoc: 123}, {subDoc: 234} ]},
    {field: [ {subDoc: 234}, {subDoc: 345} ]},
    {field: [ {subDoc: 123}, {subDoc: 345}, {subDoc: 456} ]}
]

      

and the list of user-given ids is 123, 234, 345

, I need to get a count of the given ids, so the result comes close to this:

{
    123: 2,
    234: 2,
    345: 2
}

      

What would be the best way to do this?

+3


source to share


2 answers


The aggregation framework itself, unless dynamically naming the keys as you presented as the suggested output, is probably really good. But you can probably just make a request like this:

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 }
    }}
])

      

This gives you output like this:

{ "_id" : 345, "count" : 2 }
{ "_id" : 234, "count" : 2 }
{ "_id" : 123, "count" : 2 }

      

But if you really want to go crazy, you specify the "keys" you want as part of your request, so you can create a pipeline like this:



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
                ]
            }
        }
    }}
])

      

Which is a relatively straightforward thing, to build the last step of the code just by processing the argument list:

var list = [123,234,345];

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

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

      

And it is more or less like how you want it.

{ 
    "_id" : null, 
    "123" : 2, 
    "234" : 2, 
    "345" : 2 
}

      

+5


source


Not exactly what you are asking for, but it might give you an idea:

    db.test.aggregate([
    {
        $unwind: '$field'
    },
    {
        $group: {
            _id: {
                subDoc: '$field.subDoc'
            },
            count: {
                $sum: 1
            }
        }
    },
    {
        $project: {
            subDoc: '$subDoc.subDoc',
            count: '$count'
        }
    }
]);

      



Output:

 {
    "result": [
        {
            "_id": {
                "subDoc": 456
            },
            "count": 1
        },
        {
            "_id": {
                "subDoc": 345
            },
            "count": 2
        },
        {
            "_id": {
                "subDoc": 234
            },
            "count": 2
        },
        {
            "_id": {
                "subDoc": 123
            },
            "count": 2
        }
    ],
    "ok": 1
}

      

0


source







All Articles