29

I have a document similar to the following, where I want to return a field of the current top level documents as the top level document itself in the results array:

{ 
  field1:{contents:{}}
  field2:{othercontent:{}}
}

I want the results of my aggregation query to return the following

{
  contents:{}
}

Can this be done with $project and the aggregation framework?

Gary Sharpe
  • 2,369
  • 8
  • 30
  • 51

2 Answers2

37

Yes, you can use $project to do that. You just have to tell it to retrieve the nested contents object using dot notation:

db.items.aggregate( {$project: {contents:'$field1.contents'}} );

Additionally, if you want to to hide the _id field from the output, you can specify _id: 0 in the $project parameters:

db.items.aggregate( {$project: {contents:'$field1.contents', _id:0}} );
Cristian Lupascu
  • 39,078
  • 16
  • 100
  • 137
  • 1
    Thanks, @w0lf. I realize now that I didn't quite frame my question to correctly relate my problem, but your answer above is perfect for the question as written. I've started another question to address my specific problem. http://stackoverflow.com/questions/19436510/can-i-easily-return-all-of-the-fields-of-a-subdocument-as-fields-in-the-top-leve – Gary Sharpe Oct 17 '13 at 20:22
  • Small change needed in my case: `db.items.aggregate( [ {$project: {contents:'$field1.contents'}} ] );` – rkok Sep 13 '21 at 06:20
19
  • Starting Mongo 3.4, the $replaceRoot aggregation operator can be used to replace a document by another (in our case by a sub-document):

    // { field1: { content: { a: 1, b: 2 } }, field2: { othercontent: {} } }
    // { field1: { content: { c: 1, d: 2 } }, field2: { othercontent: {} } }
    db.collection.aggregate({ $replaceRoot: { newRoot: "$field1" } })
    // { content: { a: 1, b: 2 } }
    // { content: { c: 1, d: 2 } }
    
  • Starting Mongo 4.2, the $replaceWith operator can also be used:

    db.collection.aggregate({ $replaceWith: "$field1" })
    
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190