Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to flatten a subdocument into root level in MongoDB?

For example, if I have a document like this

{
  a: 1,
  subdoc: {
    b: 2,
    c: 3
  }
}

How can I convert it into a format like this? (without using project)

{
  a: 1,
  b: 2,
  c: 3
}
like image 224
zachguo Avatar asked Apr 07 '14 04:04

zachguo


People also ask

What is $$ root in MongoDB?

The $$ROOT variable contains the source documents for the group. If you'd like to just pass them through unmodified, you can do this by $pushing $$ROOT into the output from the group.

What is replace root in MongoDB?

Definition. Replaces the input document with the specified document. The operation replaces all existing fields in the input document, including the _id field. You can promote an existing embedded document to the top level, or create a new document for promotion (see example).

What is unwind in MongoDB?

Definition. $unwind. Deconstructs an array field from the input documents to output a document for each element. Each output document is the input document with the value of the array field replaced by the element.


4 Answers

You can use MongoDB projection i.e $project aggregation framework pipeline operators as well. (recommended way). If you don't want to use project check this link

db.collection.aggregation([{$project{ . . }}]);

Below is the example for your case:

db.collectionName.aggregate
([
    { 
      $project: { 
        a: 1, 
        b: '$subdoc.b', 
        c: '$subdoc.c'
      } 
    }
]);

Gives you the output as you expected i.e.

    {
        "a" : 1,
        "b" : 2,
        "c" : 3
    }
like image 104
Amol M Kulkarni Avatar answered Oct 19 '22 03:10

Amol M Kulkarni


You can use $replaceRoot with a $addFields stage as follows:

db.collection.aggregate([
    { "$addFields": { "subdoc.a": "$a" } },
    { "$replaceRoot": { "newRoot": "$subdoc" }  }
])
like image 25
chridam Avatar answered Oct 19 '22 04:10

chridam


We can do this with $replaceWith an alias for $replaceRoot and the $mergeObjects operator.

let pipeline = [
   {
      "$replaceWith": {
         "$mergeObjects": [ { "a": "$a" }, "$subdoc" ]
      }
   }
];

or

let pipeline = [
    {
        "$replaceRoot": {
            "newRoot": {
                "$mergeObjects": [{ "a": "$a" }, "$subdoc" ]
            }
        }
    }
];

db.collection.aggregate(pipeline)
like image 23
styvane Avatar answered Oct 19 '22 03:10

styvane


You can also use $$ROOT in $mergeObjects

{ $replaceWith: {
        $mergeObjects: [ "$$ROOT", "$subdoc" ]
} }
like image 6
daniel Avatar answered Oct 19 '22 04:10

daniel