Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-23313

Add a $replaceRoot stage which allows promoting a sub-document to the top level

    • Type: Icon: New Feature New Feature
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 3.3.11
    • 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).

            Assignee:
            carly.robison Carly Robison
            Reporter:
            charlie.swanson@mongodb.com Charlie Swanson
            Votes:
            0 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated:
              Resolved: