Note
The MongoDB Search embeddedDocuments type, embeddedDocument operator, and embedded scoring option are in preview.
Definition
embeddedDocumentThe
embeddedDocumentoperator is similar to $elemMatch operator. It constrains multiple query predicates to be satisfied from a single element of an array of embedded documents.embeddedDocumentcan be used only for queries over fields of the embeddedDocuments type.
Syntax
embeddedDocument has the following syntax:
{ "embeddedDocument": { "path": "<path-to-field>", "operator": { <operator-specification> }, "score": { <score-options> } } }
Options
embeddedDocument uses the following options to construct a query:
Field | Type | Description | Necessity |
|---|---|---|---|
| object | Operator to use to query each document in the array of documents that you specify in the | Required |
| string | Indexed embeddedDocuments type field to search. The specified field must be a parent for all operators and fields specified using the | Required |
| object | Score to assign to matching search results. You can use the | Optional |
embeddedDocument Operator Limitations
You can't use highlight in queries inside the embeddedDocument operator.
Note
MongoDB Search stops replicating changes for indexes larger than 2,100,000,000 index objects per partition, on a replica set or single shard, where each indexed embedded parent document counts as a single object. Surpassing this limit may result in stale query results.
Using the embeddedDocuments field type can result in indexing objects over this index size limit, because each indexed embedded document is counted as a single object. If you create a MongoDB Search index that has or will soon have more than 2.1 billion index objects, use the numPartitions index option to partition your index (supported only on Search Nodes deployments) or shard your cluster.
Behavior
When you query embedded documents in arrays using the embeddedDocument operator, MongoDB Search evaluates and scores the operator query predicates at different stages of query execution. MongoDB Search:
Evaluates each embedded document in the array independently.
Combines the scores of matching results as configured using the
embeddedoption, or scores by summing the scores of matching results if you don't specify anembeddedscore option.Joins the matching results with the parent document if other query predicates are specified through the compound.
Scoring Behavior
By default, embeddedDocument operator uses the default aggregation strategy, sum, for combining scores of embedded document matches. The embeddedDocument operator score option allows you to override the default and configure the score of matching results using the embedded option.
Sorting Behavior
To sort the parent documents by an embedded document field, you must do the following:
Index the parents of the embedded document child field as the document type.
Index the child field with string values within the embedded document as the token type. For child fields with number and date values, enable dynamic mapping to index those fields automatically.
MongoDB Search sorts on parent documents only. It doesn't sort the child fields within an array of documents. For an example, see Sort Example.
Highlighting
You can highlight on fields if the fields are indexed under a parent field of document type for query predicates specified inside the embeddedDocument operator. For an example, see tutorial.
To learn about the embeddedDocument operator limitations, see embeddedDocument Operator Limitations.
Examples
The following examples use the sample_supplies.sales collection in the sample dataset.
Index Definition
These sample queries use the following index definition on the collection:
{ "mappings": { "dynamic": true, "fields": { "items": [ { "dynamic": true, "type": "embeddedDocuments" }, { "dynamic": true, "fields": { "tags": { "type": "token" } }, "type": "document" } ], "purchaseMethod": { "type": "token" } } } }
Basic Query
The following query searches the collection for items tagged school with a preference for items named backpack. MongoDB Search scores the results in descending order based on the average (arithmetic mean) score of all matching embedded documents. The query includes a $limit stage to limit the output to 5 documents and a $project stage to:
Exclude all fields except
items.nameanditems.tagsfieldsAdd a field named
score
1 db.sales.aggregate({ 2 "$search": { 3 "embeddedDocument": { 4 "path": "items", 5 "operator": { 6 "compound": { 7 "must": [{ 8 "text": { 9 "path": "items.tags", 10 "query": "school" 11 } 12 }], 13 "should": [{ 14 "text": { 15 "path": "items.name", 16 "query": "backpack" 17 } 18 }] 19 } 20 }, 21 "score": { 22 "embedded": { 23 "aggregate": "mean" 24 } 25 } 26 } 27 } 28 }, 29 { 30 $limit: 5 31 }, 32 { 33 $project: { 34 "_id": 0, 35 "items.name": 1, 36 "items.tags": 1, 37 "score": { $meta: "searchScore" } 38 } 39 })
[ { items: [ { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] } ], score: 1.2907354831695557 }, { items: [ { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ] }, { name: 'printer paper', tags: [ 'office', 'stationary' ] }, { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] } ], score: 1.2907354831695557 }, { items: [ { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] } ], score: 1.2907354831695557 }, { items: [ { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] } ], score: 1.2907354831695557 }, { items: [ { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] } ], score: 1.2907354831695557 } ]
Facet Query
The following query searches for items tagged school with a preference for items named backpack. It requests facet information on the purchaseMethod field.
1 db.sales.aggregate({ 2 "$searchMeta": { 3 "facet": { 4 "operator": { 5 "embeddedDocument": { 6 "path": "items", 7 "operator": { 8 "compound": { 9 "must": [ 10 { 11 "text": { 12 "path": "items.tags", 13 "query": "school" 14 } 15 } 16 ], 17 "should": [ 18 { 19 "text": { 20 "path": "items.name", 21 "query": "backpack" 22 } 23 } 24 ] 25 } 26 } 27 } 28 }, 29 "facets": { 30 "purchaseMethodFacet": { 31 "type": "string", 32 "path": "purchaseMethod" 33 } 34 } 35 } 36 } 37 })
[ { count: { lowerBound: Long("2309") }, facet: { purchaseMethodFacet: { buckets: [ { _id: 'In store', count: Long("2751") }, { _id: 'Online', count: Long("1535") }, { _id: 'Phone', count: Long("578") } ] } } } ]
Query and Sort
The following query searches for items named laptop and it sorts the results by the items.tags field. The query includes a $limit stage to limit the output to 5 documents and a $project stage to:
Exclude all fields except
items.nameanditems.tagsAdd a field named
score
1 db.sales.aggregate({ 2 "$search": { 3 "embeddedDocument": { 4 "path": "items", 5 "operator": { 6 "text": { 7 "path": "items.name", 8 "query": "laptop" 9 } 10 } 11 }, 12 "sort": { 13 "items.tags": 1 14 } 15 } 16 }, 17 { 18 "$limit": 5 19 }, 20 { 21 "$project": { 22 "_id": 0, 23 "items.name": 1, 24 "items.tags": 1, 25 "score": { "$meta": "searchScore" } 26 } 27 })
1 [ 2 { 3 items: [ 4 { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ] }, 5 { name: 'binder', tags: [ 'school', 'general', 'organization' ] }, 6 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 7 { name: 'laptop', tags: [ 'electronics', 'school', 'office' ] }, 8 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 9 { name: 'printer paper', tags: [ 'office', 'stationary' ] }, 10 { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] }, 11 { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ] }, 12 { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ] } 13 ], 14 score: 1.168686032295227 15 }, 16 { 17 items: [ 18 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 19 { name: 'binder', tags: [ 'school', 'general', 'organization' ] }, 20 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 21 { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ] }, 22 { name: 'printer paper', tags: [ 'office', 'stationary' ] }, 23 { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ] }, 24 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 25 { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] }, 26 { name: 'laptop', tags: [ 'electronics', 'school', 'office' ] } 27 ], 28 score: 1.168686032295227 29 }, 30 { 31 items: [ 32 { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] }, 33 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 34 { name: 'binder', tags: [ 'school', 'general', 'organization' ] }, 35 { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ] }, 36 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 37 { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ] }, 38 { name: 'laptop', tags: [ 'electronics', 'school', 'office' ] } 39 ], 40 score: 1.168686032295227 41 }, 42 { 43 items: [ 44 { name: 'laptop', tags: [ 'electronics', 'school', 'office' ] }, 45 { name: 'binder', tags: [ 'school', 'general', 'organization' ] }, 46 { name: 'binder', tags: [ 'school', 'general', 'organization' ] }, 47 { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] }, 48 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 49 { name: 'printer paper', tags: [ 'office', 'stationary' ] }, 50 { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ] }, 51 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 52 { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ] }, 53 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] } 54 ], 55 score: 1.168686032295227 56 }, 57 { 58 items: [ 59 { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ] }, 60 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 61 { name: 'notepad', tags: [ 'office', 'writing', 'school' ] }, 62 { name: 'backpack', tags: [ 'school', 'travel', 'kids' ] }, 63 { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ] }, 64 { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ] }, 65 { name: 'binder', tags: [ 'school', 'general', 'organization' ] }, 66 { name: 'laptop', tags: [ 'electronics', 'school', 'office' ] }, 67 { name: 'printer paper', tags: [ 'office', 'stationary' ] }, 68 { name: 'binder', tags: [ 'school', 'general', 'organization' ] } 69 ], 70 score: 1.168686032295227 71 } 72 ]
Query for Matching Embedded Documents Only
The following query returns only the nested documents that match the query. The query uses MongoDB Search compound operator clauses in the $search stage to find matching documents and then the aggregation operators in the $project stage to return only matching embedded documents. Specifically, the query specifies the following pipeline stages:
Specifies the following criteria in the compound operator
| |
Limits the output to | |
1 db.sales.aggregate( 2 { 3 "$search": { 4 "embeddedDocument": { 5 "path": "items", 6 "operator": { 7 "compound": { 8 "must": [ 9 { 10 "range": { 11 "path": "items.quantity", 12 "gt": 2 13 } 14 }, 15 { 16 "exists": { 17 "path": "items.price" 18 } 19 }, 20 { 21 "text": { 22 "path": "items.tags", 23 "query": "school" 24 } 25 } 26 ] 27 } 28 } 29 } 30 } 31 }, 32 { 33 "$limit": 2 34 }, 35 { 36 "$project": { 37 "_id": 0, 38 "storeLocation": 1, 39 "items": { 40 "$filter": { 41 "input": "$items", 42 "cond": { 43 "$and": [ 44 { 45 "$ifNull": [ 46 "$$this.price", "false" 47 ] 48 }, 49 { 50 "$gt": [ 51 "$$this.quantity", 2 52 ] 53 }, 54 { 55 "$in": [ 56 "office", "$$this.tags" 57 ] 58 } 59 ] 60 } 61 } 62 } 63 } 64 } 65 )
1 [ 2 { 3 storeLocation: 'Austin', 4 items: [ 5 { 6 name: 'laptop', 7 tags: [ 'electronics', 'school', 'office' ], 8 price: Decimal128('753.04'), 9 quantity: 3 10 }, 11 { 12 name: 'pens', 13 tags: [ 'writing', 'office', 'school', 'stationary' ], 14 price: Decimal128('19.09'), 15 quantity: 4 16 }, 17 { 18 name: 'notepad', 19 tags: [ 'office', 'writing', 'school' ], 20 price: Decimal128('30.23'), 21 quantity: 5 22 }, 23 { 24 name: 'pens', 25 tags: [ 'writing', 'office', 'school', 'stationary' ], 26 price: Decimal128('20.05'), 27 quantity: 4 28 }, 29 { 30 name: 'notepad', 31 tags: [ 'office', 'writing', 'school' ], 32 price: Decimal128('22.08'), 33 quantity: 3 34 }, 35 { 36 name: 'notepad', 37 tags: [ 'office', 'writing', 'school' ], 38 price: Decimal128('21.67'), 39 quantity: 4 40 } 41 ] 42 }, 43 { 44 storeLocation: 'Austin', 45 items: [ 46 { 47 name: 'notepad', 48 tags: [ 'office', 'writing', 'school' ], 49 price: Decimal128('24.16'), 50 quantity: 5 51 }, 52 { 53 name: 'notepad', 54 tags: [ 'office', 'writing', 'school' ], 55 price: Decimal128('28.04'), 56 quantity: 5 57 }, 58 { 59 name: 'notepad', 60 tags: [ 'office', 'writing', 'school' ], 61 price: Decimal128('21.42'), 62 quantity: 5 63 }, 64 { 65 name: 'laptop', 66 tags: [ 'electronics', 'school', 'office' ], 67 price: Decimal128('1540.63'), 68 quantity: 3 69 }, 70 { 71 name: 'pens', 72 tags: [ 'writing', 'office', 'school', 'stationary' ], 73 price: Decimal128('29.43'), 74 quantity: 5 75 }, 76 { 77 name: 'pens', 78 tags: [ 'writing', 'office', 'school', 'stationary' ], 79 price: Decimal128('28.48'), 80 quantity: 5 81 } 82 ] 83 } 84 ]
Tip
To return only matching embedded documents in the results, include an equivalent $filter to match the $search criteria on the embedded document field. To return only matching embedded documents in the $search stage results, upvote this request in the MongoDB Feedback Engine.
Learn More
To learn more, see How to Run MongoDB Search Queries Against Fields in Embedded Documents.