Vidya
Vidya

Reputation: 30300

Aggregating Groups of Documents By Field

I have a MongoDB collection with a particular field , call it target, that looks like this:

{ "a": 123, "target": 1 }
{ "a": 456, "target": 2 }
{ "a": 324, "target": 3 }
{ "a": 333, "target": 1 }
{ "a": 678, "target": 1 }
{ "a": 789, "target": 2 }
{ "a": 555, "target": 3 }

I would like to know if there is a way to accomplish the following conceptually (if not necessarily literally):

[
   { "target": 1, [{ "a": 123, "target": 1 }, { "a": 333, "target": 1 }, { "a": 678, "target": 1 }] },
   { "target": 2, [{ "a": 456, "target": 2 }, { "a": 789, "target": 2 }] },
   { "target": 3, [{ "a": 324, "target": 3 }, { "a": 555, "target": 3 }] }
]

Basically, I would like a mapping of target values to all the documents containing those target values, but reading and re-reading the documentation hasn't helped me figure out how to do this with the aggregation framework or anything else. I would like to know if this is possible before I set about doing this in my application code.

Upvotes: 0

Views: 46

Answers (2)

Tug Grall
Tug Grall

Reputation: 3510

AFAIK, it won't be possible to create a "single array" that contains all the results; however what you can do is to create a document for each group (target) as described below.

You will be able to achieve this by doing a $push in your group

db.collection.aggregate([
  {$group : {  "_id" : "$target" , "values" :{ $push:  { a : "$a" , target : "$target"  }  } } },
  {$project : { "_id" : 0 ,  "values" : 1, "target" : "$_id" , }  }
]);

the result will be something like :

{
    "values": [
    {
        "a": 324,
        "target": 3
    },
    {
        "a": 555,
        "target": 3
    }
    ],
    "target": 3
}{
    "values": [
    {
        "a": 456,
        "target": 2
    },
    {
        "a": 789,
        "target": 2
    }
    ],
    "target": 2
}{
    "values": [
    {
        "a": 123,
        "target": 1
    },
    {
        "a": 333,
        "target": 1
    },
    {
        "a": 678,
        "target": 1
    }
    ],
    "target": 1
}

As you can see, I have added a name to the array "values" since your result example is not a valid JSON document

You can also add the $out step that will save the result of this aggregation in a new collection

But you have to be very careful with such aggregation, since you are building an array in your results: keep in mind that a document could not be bigger than 16Mb. So if you have "too" many entries for a target you may reach this limit.

Upvotes: 2

Neo-coder
Neo-coder

Reputation: 7840

Hi as per your question I found some way you can achieve this it not exactly what you expected but it matches your criteria below aggregation may help you

    db.collectionName.aggregate([
    {
    "$group": {
        "_id": {
            "a": "$a",
            "target": "$target"
        }
    }
    },
    {
    "$group": {
        "_id": "$_id.target",
        "targetData": {
            "$push": {
                "a": "$_id.a",
                "target": "$_id.target"
            }
        }
    }
    }
])

Upvotes: 1

Related Questions