-
Type: New Feature
-
Resolution: Done
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: Aggregation Framework
-
None
-
Fully Compatible
-
Integration 18 (08/05/16)
Syntax
{$replaceRoot: {newRoot: <expression that evaluates to a document>}}
Examples
// ===== Example #1 - Promoting a subfield to the top level ===== >db.example.insert({_id: 0, a1: {b: 1}, a2: 2}) >db.example.aggregate([{$replaceRoot: {newRoot: “$a1”}}]); {b: 1} // ===== Example #2 - Promoting a nested field to the top level ===== >db.example.insert({_id: 0, a1: {b: {c1: 4, c2: 5}}, a2: 2}) >db.example.aggregate([{$replaceRoot: {newRoot: “$a1.b”}}]) {_id: 0, c1: 4, c2: 5} // ===== Example #3 - Promoting a field that contains an _id ===== >db.example.insert({_id: 0, a1: {b: 1, _id: 7}, a2: 2}) >db.example.aggregate([{$replaceRoot: {newRoot: “$a1”}}]); {b: 1, _id: 7} // ===== Errors #1 - Invalid path syntax ===== >db.example.aggregate([{$replaceRoot: “$a” }]) Error: expected an object as specification for $replaceRoot stage // ===== Error #2 - When the field doesn’t exist ===== >db.example.insert({_id: 0, a1: {b: 1}, a2: 2}) >db.example.aggregate([{$replaceRoot: {newRoot: “$c”}}]) Error: newRoot must resolve to an object // ===== Error #3 - When the field is not an object ===== >db.example.insert({_id: 0, a1: {b: 1}, a2: 2 }) >db.example.aggregate([{$replaceRoot: {newRoot: “$a2”}}]) Error: newRoot must resolve to an object
More Details
- We do not do anything special with the _id field.
- The original _id (if it exists) will be lost. The user can include it by prepending a {$addFields: {“a._id”: “$_id”}} stage. Any _id field in the new root will not be moved to the front for display.
Original Description
In some cases, the documents of interest in the aggregation pipeline are nested inside an outer document. For example, if I had a schema like this:
{ _id: "user_id", first: "first name", last: "last name", addresses: [ {city: "New York", state: "NY", zip: "10036", address: "229 W 43rd"}, {city: "Palo Alto", state: "CA", zip: "94301", address: "100 Forest Ave"} ... ] }
Then I might have an aggregation pipeline which deals exclusively with the contents of 'addresses'. It's currently possible to do this, first by unwinding 'addresses', but this approach becomes annoying since all of the field names need to be prefixed with 'addresses.'. It would be useful to have some stage to promote the document inside 'addresses' to the top field. For example, something like this:
db.users.aggregate([ {$unwind: "$addresses"}, {$transform: {root: "$addresses"}} ]) {city: "New York", state: "NY", zip: "10036", address: "229 W 43rd"} {city: "Palo Alto", state: "CA", zip: "94301", address: "100 Forest Ave"}
Such a stage could also support other transformations, like those possible in $project, or some that are not possible, such as adding a field to a document (SERVER-5781).
- is depended on by
-
CSHARP-1742 Add support for $replaceRoot aggregation stage
- Closed
-
JAVA-2287 Add builder for $replaceRoot aggregation stage
- Closed
- is duplicated by
-
SERVER-24779 Add a $transform aggregation stage
- Closed
- related to
-
DRIVERS-297 Aggregation Framework Support for 3.4
- Closed
-
SERVER-25604 Improve readability/usefulness of $replaceRoot error messages
- Closed