kidbrax
kidbrax

Reputation: 2434

How can I collect all subdocuments into a single array

How can I collect all the subdocuments of a collection into a single array? Say I have these documents in my collection:

/* 0 */
{
    "_id" : ObjectId("52d709d8cdcc16fa35834320"),
    "start_date" : ISODate("2012-10-31T00:00:00.000Z"),
    "end_date" : ISODate("2012-11-13T00:00:00.000Z"),
    "items" : [
        {
            "upc" : "",
        }
    ],
}

/* 1 */
{
    "_id" : ObjectId("52d709d8cdcc16fa35834321"),
    "modified_at" : ISODate("2014-01-15T22:16:06.991Z"),
    "start_date" : ISODate("2012-10-31T00:00:00.000Z"),
    "end_date" : ISODate("2012-11-13T00:00:00.000Z"),
    "items" : [
        {
            "upc" : "",
        }
    ],
}

/* 2 */
{
    "_id" : ObjectId("654321973387fa1fa7777777"),
    "start_date" : ISODate("2012-10-31T00:00:00.000Z"),
    "end_date" : ISODate("2012-11-13T00:00:00.000Z"),
    "items" : [
        {
            "upc" : "",
        },
        {
            "upc" : "",
        }
    ],
}

I don't need to do anyting fancy such as summing or calculating anything. I just want to extract the subdocuments and end up with this:

[
    { "upc" : "123" },
    { "upc" : "456" },
    { "upc" : "789" },
    { "upc" : "012" }
]

I know there has to be a simple way to do this, but I am not having any luck.

Upvotes: 1

Views: 566

Answers (1)

Kenneth
Kenneth

Reputation: 300

I've done something similar, it can be achieved via the aggregation framework (http://docs.mongodb.org/manual/aggregation/). You could try a query like this ( Disclaimer : untested I usually build queries in C#)

db.collection.aggregate({
   { $unwind : "$items"}, 
   { $group: { 
      _id: null, 
      items: 
        { $push: "$items" } 
   }} 
}

If the syntax is correct, the query should hit every document and unwrap all the elements in the "items" array for every document. It then groups this together in a single document with "$group" and "$push" (operators explained here http://docs.mongodb.org/manual/reference/operator/aggregation/group/). This should produces a structure as such:

{
   items:[
      { "upc" : "123" },
      { "upc" : "456" },
      { "upc" : "789" },
      { "upc" : "012" }"
   ] 
}

if it produces more you should add a $project step at the end of the pipeline (http://docs.mongodb.org/manual/core/aggregation-pipeline/)(http://docs.mongodb.org/manual/reference/operator/aggregation/project/).

You can go further and optimize it by adding a $match step to filter the documents before unwinding, and even filter the results in the array ($match -> $unwind -> $match -> $group). (http://docs.mongodb.org/manual/reference/operator/aggregation/match/)

Hope this helps and GL!

Upvotes: 5

Related Questions