> 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

```json
{
  $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:

```none
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

```json
{
  "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.

```json
{
  ...,
  "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.

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

**Output:**

```javascript
[
  {
    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.

```javascript
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:**

```javascript
[
  {
    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.

```javascript
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:**

```javascript
[
  {
    _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.

```javascript
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:**

```javascript
[
  {
    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' }
  }
]

```
