70

I have a deeply nested collection in my MongoDB collection.

When I run the following query:

db.countries.findOne({},{'data.country.neighbor.name':1,'_id':0})

I end up with this nested result here:

{"data" : {
  "country" : [
    {
      "neighbor" : [
        {
          "name" : "Austria"
        },
        {
          "name" : "Switzerland"
        }
      ]
    },
    {
      "neighbor" : {
        "name" : "Malaysia"
      }
    },
    {
      "neighbor" : [
        {
          "name" : "Costa Rica"
        },
        {
          "name" : "Colombia"
        }
      ]
    }
  ]
}}

Now, this is what I want:

['Austria', 'Switzerland', 'Malaysia', 'Costa Rica', 'Colombia']

or this:

{'name':['Austria', 'Switzerland', 'Malaysia', 'Costa Rica', 'Colombia']}

or anything else similar... Is this possible?

Marsellus Wallace
  • 17,991
  • 25
  • 90
  • 154

4 Answers4

90

You can use $project & $unwind & $group of aggregation framework to get the result closer to your requirement.

> db.countries.aggregate({$project:{a:'$data.country.neighbor.name'}},
                         {$unwind:'$a'},
                         {$unwind:'$a'},
                         {$group:{_id:'a',res:{$addToSet:'$a'}}})
  {
    "result" : [
        {
            "_id" : "a",
            "res" : [
                "Colombia",
                "Malaysia",
                "Switzerland",
                "Costa Rica",
                "Austria"
            ]
        }
    ],
    "ok" : 1
}

$unwind used twice since the name array is nested deep. And It will only work if the neighbor attribute is an array. In your example one neighbor field (Malaysia) is not an array

RameshVel
  • 64,778
  • 30
  • 169
  • 213
13

Done it much simpler way, maybe it is recent

db.countries.aggregate({$unwind:'$data.country.neighbor.name'})
wadouk
  • 131
  • 1
  • 4
2

To flatten your data you can also use $reduce. Here is an example in the docs.

db.countries.aggregate([
  {
    $addFields: {
      newField: {
        $reduce: {
          input: "$data.country.neighbor.name",
          initialValue: [],
          in: { $concatArrays: ["$$value", "$$this"] }
        }
      }
    }
  }
])
-7

It's pretty straightforward under the new aggregation framework. The $project and $unwind operation are right for the purpose.

James Gan
  • 6,988
  • 4
  • 28
  • 36