return-scope

For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt

<!-- Tab options on this page. Append to the .md URL to filter: ?tabs=<id,...> select specific tabs (e.g. ?tabs=nodejs,shell) ?allTabs=true include every tab (no param) default: one tab per tabset

Available tabs: other tabs: search, search-meta -->

Query, Filter, and Retrieve Arrays of Objects

You can use the returnScope option to set the context of the query and return arrays of objects as individual documents.

Requirements

To retrieve nested objects as individual documents using returnScope, you must:

  • Index the arrays of objects as the [embeddedDocuments](https://www.mongodb.com/docs/search/indexes/field-types/embedded-documents-type.md#std-label-bson-data-types-embedded-documents type.

  • Define [storedSource](https://www.mongodb.com/docs/search/indexes/stored-source-definition.md#std-label-fts-stored-source-definition for the nested fields that you want to retrieve. MongoDB Search only returns fields defined in the storedSource.

  • Set the [returnStoredSource](https://www.mongodb.com/docs/search/query/return-stored-source.md#std-label-fts-return-stored-source-option option to true in the query.

Syntax

returnScope has the following syntax in your queries:

$search Syntax

{
  $search: {
   "<operator>": {
      <operator-specification>,
   },
   "returnScope": {
      "path": "<embedded-documents-field-to-retrieve>"
   },
   "returnStoredSource": true
  }
}

To learn more about query syntax, see [$search.](https://www.mongodb.com/docs/search/query/aggregation-stages/search.md#mongodb-pipeline-pipe.-search

Behavior

The returnScope option sets the retrieval context for the query. If you specify returnScope in your query, MongoDB Search scores, sorts, and counts each embedded document as if it were an individual document.

Considerations

When you use the returnScope option, MongoDB Search only returns the fields that you configured as storedSource within the embeddedDocument. Fields outside of the embeddedDocument path (such as fields at the root level) and fields that are not configured as storedSource are not returned.

In your operator specification, you must specify the full path to the field that you want to query. When you use the returnScope option, you must make sure all operator specifications paths are nested under the returnScope.path. To query on a field outside the returnScope.path, you must use either the hasAncestor or hasRoot operator. To learn more, see:

  • [hasAncestor Operator](https://www.mongodb.com/docs/search/query/operators-collectors/hasancestor.md#std-label-has-ancestor-ref

  • [hasRoot Operator](https://www.mongodb.com/docs/search/query/operators-collectors/hasroot.md#std-label-has-root-ref

Retrieve the Root Document ID

When you use returnScope in a query, MongoDB Search populates a searchRootDocumentId metadata field. You can use the searchRootDocumentId metadata field on clusters running MongoDB 8.3 or later. This field contains the identifier of the root document that contains each returned embedded document. To project this value, use the [$meta](https://www.mongodb.com/docs/manual/reference/operator/aggregation/meta.md#mongodb-expression-exp.-meta expression with the searchRootDocumentId keyword.

MongoDB Search populates searchRootDocumentId only when your query sets both returnStoredSource: true and returnScope.path. If you reference searchRootDocumentId in a query that does not specify returnScope, the query fails with the following error:

query requires $search root document id metadata, but it is not
available

Use searchRootDocumentId if you want to:

  • Fetch fields from the parent document after filtering on the child documents.

  • Group child documents by their parent.

Don't use searchRootDocumentId if:

  • You need only fields from the matched child documents.

  • You want to return the parent document for every child document in the result set, since this can be expensive.

Examples

The following examples demonstrate how to use the returnScope option in queries. The examples use the sample_training.companies sample dataset. If you load the data on your cluster and create the sample index on the fields in the collection, you can try the following queries against the sample data.

Sample Index

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "funding_rounds": {
        "type": "embeddedDocuments",
        "dynamic": true,
        "fields": {
          "investments": {
            "type": "embeddedDocuments",
            "dynamic": true
          }
        },
        "storedSource": {
          "include": [
            "round_code",
            "raised_currency_code",
            "raised_amount",
            "investments.person",
            "investments.financial_org"
          ]
        }
      }
    }
  }
}

The preceding index definition configures MongoDB Search to:

  • Index the funding_rounds and funding_rounds.investments fields as the embeddedDocuments type.

  • Index all the dynamically indexable fields nested in the funding_rounds and funding_rounds.investments array of objects.

  • Store the following fields on mongot:

  • funding_rounds.round_code

  • funding_rounds.raised_currency_code

  • funding_rounds.raised_amount

  • funding_rounds.investments.person

  • funding_rounds.investments.financial_org

You can use the [embeddedDocument Operator](https://www.mongodb.com/docs/search/query/operators-collectors/embedded-document.md#std-label-embedded-document-ref to perform element-wise querying on both the funding_rounds and funding_rounds.investments fields. The following sections demonstrate some sample queries that use the returnScope option to retrieve the embeddedDocuments fields as individual documents.

{
  ...,
  "funding_rounds": [
    {
      "id": <integer>,
      "round_code": "<string>",
      "source_url": "<string>",
      "source_description": "<string>",
      "raised_amount": <integer>,
      "raised_currency_code": "<string>",
      "funded_year": <integer>,
      "funded_month": "<string>",
      "funded_day": "<string>",
      "investments": [
         {
           "company": "<string>",
           "financial_org": {
             "name": "<string>",
             "permalink": "<string>"
           },
           "person": {
             "first_name": "<string>",
             "last_name": "<string>",
             "permalink": "<string>"
           }
         },
         ...
      ]
    },
    ...
  ],
  ...
}

Sample Queries

The following sections demonstrate sample queries that use the returnScope option to retrieve fields in embeddedDocuments type fields that were stored on mongot.

Simple Query

Query and retrieve embedded document fields.

The following query uses the [range (MongoDB Search Operator)](https://www.mongodb.com/docs/search/query/operators-collectors/range.md#std-label-range-ref to query the funding_rounds.raised_amount field for amount greater than and equal to 5000000 and less than and equal to 10000000. It sets the query scope as funding_rounds field using the returnScope option. It returns all the stored fields inside the funding_rounds array of objects, including fields in the funding_rounds.investments array of objects that were stored using the returnStoredSource option. It limits the number of results to only 5 funding_rounds documents.

db.companies.aggregate(
  {
    "$search": {
      "range": {
        "path": "funding_rounds.raised_amount",
        "gte": 5000000,
        "lte": 10000000
      },
      "returnStoredSource": true,
      "returnScope": {
        "path": "funding_rounds"
      }
    }
  },
  {
    "$limit": 5
  }
)

Output:

[
  {
    round_code: 'a',
    raised_amount: 5250000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: {
          name: 'Frazier Technology Ventures',
          permalink: 'frazier-technology-ventures'
        },
        person: null
      },
      {
        financial_org: { name: 'Trinity Ventures', permalink: 'trinity-ventures' },
        person: null
      }
    ]
  },
  {
    round_code: 'b',
    raised_amount: 9500000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: { name: 'Accel Partners', permalink: 'accel-partners' },
        person: null
      },
      {
        financial_org: {
          name: 'Frazier Technology Ventures',
          permalink: 'frazier-technology-ventures'
        },
        person: null
      },
      {
        financial_org: { name: 'Trinity Ventures', permalink: 'trinity-ventures' },
        person: null
      }
    ]
  },
  {
    round_code: 'a',
    raised_amount: 5000000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: {
          name: 'Charles River Ventures',
          permalink: 'charles-river-ventures'
        },
        person: null
      },
      {
        financial_org: {
          name: 'Union Square Ventures',
          permalink: 'union-square-ventures'
        },
        person: null
      },
      {
        financial_org: null,
        person: {
          first_name: 'Marc',
          last_name: 'Andreessen',
          permalink: 'marc-andreessen'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Dick',
          last_name: 'Costolo',
          permalink: 'dick-costolo'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Naval',
          last_name: 'Ravikant',
          permalink: 'naval-ravikant'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Ron',
          last_name: 'Conway',
          permalink: 'ron-conway'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Chris',
          last_name: 'Sacca',
          permalink: 'chris-sacca'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Greg',
          last_name: 'Yaitanes',
          permalink: 'greg-yaitanes'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Brian',
          last_name: 'Pokorny',
          permalink: 'brian-pokorny'
        }
      },
      {
        financial_org: { name: 'SV Angel', permalink: 'sv-angel' },
        person: null
      }
    ]
  },
  {
    round_code: 'e',
    raised_amount: 5166511,
    raised_currency_code: 'USD',
    investments: []
  },
  {
    round_code: 'b',
    raised_amount: 9000000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: {
          name: 'Charles River Ventures',
          permalink: 'charles-river-ventures'
        },
        person: null
      },
      {
        financial_org: { name: 'Redpoint Ventures', permalink: 'redpoint-ventures' },
        person: null
      },
      {
        financial_org: {
          name: 'The Kinsey Hills Group',
          permalink: 'kinsey-hills-group'
        },
        person: null
      }
    ]
  }
]

Compound Query

Query and retrieve multiple embedded document fields.

The following query uses the [compound Operator](https://www.mongodb.com/docs/search/query/operators-collectors/compound.md#std-label-compound-ref to search multiple levels of nested embeddedDocuments fields in the same query:

  • Must match``funding_rounds.raised_currency_code`` with USD

  • Should match funding_rounds.investments.financial_org.name with Trinity Ventures

It returns all the stored fields inside the funding_rounds array of objects, including fields in the funding_rounds.investments. It limits the number of results to only 5 funding_rounds documents.

db.companies.aggregate(
  {
    "$search": {
      "compound": {
        "must": [{
          "text": {
            "path": "funding_rounds.raised_currency_code",
            "query": "usd"
          }
        }],
        "should": [{
          "phrase": {
            "path": "funding_rounds.investments.financial_org",
            "query": "Trinity Ventures",
          }
        }]
      },
      "returnStoredSource": true,
      "returnScope": {
        "path": "funding_rounds"
      }
    }
  },
  {
    "$limit": 5
  }
)

Output:

[
  {
    round_code: 'a',
    raised_amount: 5250000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: {
          name: 'Frazier Technology Ventures',
          permalink: 'frazier-technology-ventures'
        },
        person: null
      },
      {
        financial_org: { name: 'Trinity Ventures', permalink: 'trinity-ventures' },
        person: null
      }
    ]
  },
  {
    round_code: 'b',
    raised_amount: 9500000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: { name: 'Accel Partners', permalink: 'accel-partners' },
        person: null
      },
      {
        financial_org: {
          name: 'Frazier Technology Ventures',
          permalink: 'frazier-technology-ventures'
        },
        person: null
      },
      {
        financial_org: { name: 'Trinity Ventures', permalink: 'trinity-ventures' },
        person: null
      }
    ]
  },
  {
    round_code: 'c',
    raised_amount: 25000000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: { name: 'DAG Ventures', permalink: 'dag-ventures' },
        person: null
      },
      {
        financial_org: { name: 'Accel Partners', permalink: 'accel-partners' },
        person: null
      },
      {
        financial_org: { name: 'Trinity Ventures', permalink: 'trinity-ventures' },
        person: null
      },
      {
        financial_org: {
          name: 'Frazier Technology Ventures',
          permalink: 'frazier-technology-ventures'
        },
        person: null
      }
    ]
  },
  {
    round_code: 'angel',
    raised_amount: 500000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: null,
        person: {
          first_name: 'Peter',
          last_name: 'Thiel',
          permalink: 'peter-thiel'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Reid',
          last_name: 'Hoffman',
          permalink: 'reid-hoffman'
        }
      }
    ]
  },
  {
    round_code: 'a',
    raised_amount: 12700000,
    raised_currency_code: 'USD',
    investments: [
      {
        financial_org: { name: 'Accel Partners', permalink: 'accel-partners' },
        person: null
      },
      {
        financial_org: null,
        person: {
          first_name: 'Mark',
          last_name: 'Pincus',
          permalink: 'mark-pincus'
        }
      },
      {
        financial_org: null,
        person: {
          first_name: 'Reid',
          last_name: 'Hoffman',
          permalink: 'reid-hoffman'
        }
      }
    ]
  }
]

Group Children by Parent

Group children by parent using the searchRootDocumentId meta field.

The following query uses the [range (MongoDB Search Operator)](https://www.mongodb.com/docs/search/query/operators-collectors/range.md#std-label-range-ref to query the funding_rounds.raised_amount field for amount greater than and equal to 5000000 and less than and equal to 10000000. It sets the query scope as funding_rounds field using the returnScope option. It groups the matching funding_rounds under each parent company by using the searchRootDocumentId meta field as the group key and computes the average raised_amount per company in the avgRaisedAmount field. It sorts the results by avgRaisedAmount in descending order and limits the number of results to 10 companies.

db.companies.aggregate([
  {
    "$search": {
      "returnStoredSource": true,
      "returnScope": {
        "path": "funding_rounds"
      },
      "range": {
        "path": "funding_rounds.raised_amount",
        "gte": 5000000,
        "lte": 10000000
      }
    }
  },
  {
    "$group": {
      "_id": { "$meta": "searchRootDocumentId" },
      "funding_rounds": {
        "$push": {
          "round_code": "$round_code",
          "raised_amount": "$raised_amount",
          "raised_currency_code": "$raised_currency_code"
        }
      },
      "avgRaisedAmount": { "$avg": "$raised_amount" }
    }
  },
  { "$sort": { "avgRaisedAmount": -1 } },
  { "$limit": 10 }
])

Output:

[
  {
    _id: ObjectId('52cdef7d4bab8bd675298f82'),
    funding_rounds: [
      {
        round_code: 'a',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7e4bab8bd67529af80'),
    funding_rounds: [
      {
        round_code: 'b',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7f4bab8bd67529be3d'),
    funding_rounds: [
      {
        round_code: 'a',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7f4bab8bd67529c52d'),
    funding_rounds: [
      {
        round_code: 'unattributed',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7e4bab8bd67529ab31'),
    funding_rounds: [
      {
        round_code: 'c',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      },
      {
        round_code: 'a',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7e4bab8bd67529aa94'),
    funding_rounds: [
      {
        round_code: 'b',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7f4bab8bd67529be6f'),
    funding_rounds: [
      {
        round_code: 'a',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7c4bab8bd6752985cb'),
    funding_rounds: [
      {
        round_code: 'd',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7d4bab8bd675299fd1'),
    funding_rounds: [
      {
        round_code: 'c',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  },
  {
    _id: ObjectId('52cdef7f4bab8bd67529c2c8'),
    funding_rounds: [
      {
        round_code: 'debt_round',
        raised_amount: 10000000,
        raised_currency_code: 'USD'
      }
    ],
    avgRaisedAmount: 10000000
  }
]

Fetch Parent Fields After Filtering

Retrieve the fields from the parent document after filtering on the embedded document fields.

The following query uses the [range (MongoDB Search Operator)](https://www.mongodb.com/docs/search/query/operators-collectors/range.md#std-label-range-ref to query the funding_rounds.raised_amount field for amount greater than and equal to 5000000 and less than and equal to 10000000. It sets the query scope as funding_rounds field using the returnScope option. It sorts the matching funding_rounds by raised_amount in descending order and limits the results to the top 10 funding rounds. It then uses the searchRootDocumentId meta field to join each funding round back to its parent company in the companies collection and returns the company's name alongside the funding round's round_code, raised_amount, and raised_currency_code fields.

db.companies.aggregate([
  {
    "$search": {
      "returnStoredSource": true,
      "returnScope": {
        "path": "funding_rounds"
      },
      "range": {
        "path": "funding_rounds.raised_amount",
        "gte": 5000000,
        "lte": 10000000
      }
    }
  },
  { "$sort": { "raised_amount": -1 } },
  { "$limit": 10 },
  { "$addFields": { "root_id": { "$meta": "searchRootDocumentId" } } },
  {
    "$lookup": {
      "from": "companies",
      "localField": "root_id",
      "foreignField": "_id",
      "as": "company"
    }
  },
  { "$unwind": "$company" },
  {
    "$project": {
      "_id": 0,
      "round_code": 1,
      "raised_amount": 1,
      "raised_currency_code": 1,
      "company.name": 1
    }
  }
])

Output:

[
  {
    round_code: 'partial',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'WeFi' }
  },
  {
    round_code: 'b',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'LinkedIn' }
  },
  {
    round_code: 'a',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'Lotame' }
  },
  {
    round_code: 'c',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'OpenX' }
  },
  {
    round_code: 'b',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'AddThis' }
  },
  {
    round_code: 'a',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'Terabitz' }
  },
  {
    round_code: 'b',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'Six Apart' }
  },
  {
    round_code: 'a',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'Snocap' }
  },
  {
    round_code: 'b',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'Wikia' }
  },
  {
    round_code: 'unattributed',
    raised_amount: 10000000,
    raised_currency_code: 'USD',
    company: { name: 'Mashery' }
  }
]