compound
Definition
compound
The
compound
operator combines two or more operators into a single query. Each element of acompound
query is called a clause, and each clause consists of one or more sub-queries. Atlas Search provides a sample compound query template with guidance. To learn more, see View Query Guidance Template.
Syntax
compound
has the following syntax:
1 { 2 $search: { 3 "index": <index name>, // optional, defaults to "default" 4 "compound": { 5 <must | mustNot | should | filter>: [ { <clauses> } ], 6 "score": <options> 7 } 8 } 9 }
Each must
, mustNot
, should
, and filter
clause contains
an array of subclauses. Use array syntax even if the array contains
only one subclause. See the examples on
this page.
Options
compound
uses the following terms to construct a query:
Clauses that must match to for a document to be included in the results. The returned score is the sum of the scores of all the subqueries in the clause. Maps to the | ||||||||||||||
Clauses that must not match for a document to be included in
the results. Maps to the | ||||||||||||||
Clauses that you prefer to match in documents that are included
in the results. Documents that contain a match for a If you use more than one See an example. Maps to the If you use only the | ||||||||||||||
Clauses that must all match for a document to be
included in the results. For example, you can replace the
You can use the
See another filter example. | ||||||||||||||
score | Modify the score of the entire compound
clause. You can use score to boost, replace, or otherwise
alter the score. If you don't specify score , the returned
score is the sum of the scores of all the subqueries in the
must and should clauses that generated a match. To learn
more, see Scoring Behavior. |
Usage
You can use any of the clauses with any top-level operator, such as autocomplete, text, or span, to specify query criteria.
Scoring Behavior
Atlas Search scores documents in the result set by summing the score that the
document received for each individual clause that generated a match on
the document. Only must
and should
clauses participate in
scoring. The result set is ordered by score, highest to lowest.
The following table shows the compound
clauses that contribute and
don't contribute to the score.
Clause | Contributes to Score | Doesn't Contribute to Score |
---|---|---|
filter | ||
must | ||
mustNot | ||
should |
You can boost or replace the score of the entire compound query using
the score
option. For an example of replacing the entire compound
score, see Compound Score Example below.
You can use score to also boost or alter the score
for each subquery in each clause. For some examples of altered scores in
compound
operator clauses, see Modify the Score.
Examples
You can try the following examples in the Atlas Search Playground or your Atlas cluster.
Sample Collection
The examples on this page use a collection called fruit
, which
contains the following documents:
1 { 2 "_id" : 1, 3 "type" : "apple", 4 "description" : "Apples come in several varieties, including Fuji, Granny Smith, and Honeycrisp.", 5 "category" : "nonorganic", 6 "in_stock" : false 7 }, 8 { 9 "_id" : 2, 10 "type" : "banana", 11 "description" : "Bananas are usually sold in bunches of five or six.", 12 "category" : "nonorganic", 13 "in_stock" : true 14 }, 15 { 16 "_id" : 3, 17 "type" : "pear", 18 "description" : "Bosc and Bartlett are the most common varieties of pears.", 19 "category" : "organic", 20 "in_stock" : true 21 }
Sample Index
The fruit
collection has a default index with dynamic mappings that automatically indexes all the fields in
the collection and uses the default standard analyzer. The standard
analyzer lower-cases
all words and disregards common stop words ("the", "a", "and",
etc).
Sample Queries
The following queries demonstrate the $search
compound
operator in Atlas Search queries.
must
and mustNot
Example
The following example uses a combination of must
and mustNot
clauses to contruct a query. The must
clause uses the
text operator to search for the term varieties
in the description
field. For a document to match, it must fulfill
the must
clause. The mustNot
clause performs a search operation
for the term apples
in the description
field. For a document to
match, it must not fulfill the mustNot
clause.
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "mustNot": [{ 12 "text": { 13 "query": "apples", 14 "path": "description" 15 } 16 }] 17 } 18 } 19 } 20 ])
The above query returns the document with _id: 3
because its
description
field contains the word varieties
and does not
contain apples
.
➤ Try this in the Atlas Search Playground.
must
and should
Example
The following queries use must
to specify search conditions
that must be met and should
to specify preference for documents
that contain the word Fuji
.
For this query, the $project
pipeline stage excludes all
document fields except _id
and adds a score
field, which
displays the document's relevance score.
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "Fuji", 14 "path": "description" 15 } 16 }] 17 } 18 } 19 }, 20 { 21 "$project": { 22 "score": { "$meta": "searchScore" } 23 } 24 } 25 ])
{ "_id" : 1, "score" : 0.6425117254257202 } { "_id" : 3, "score" : 0.21649497747421265 }
The document with _id: 1
has a higher score because its
description
field contains the word Fuji
, satisfying the
should
clause.
➤ Try this in the Atlas Search Playground.
The following query also specifies a constant
score of 3
for all the documents in the results. For this
query, the $project
pipeline stage excludes all document
fields except _id
and adds a score
field.
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "Fuji", 14 "path": "description" 15 } 16 }], 17 "score": { "constant": { "value": 3 } } 18 } 19 } 20 }, 21 { 22 "$project": { 23 "score": { "$meta": "searchScore" } 24 } 25 } 26 ])
[ { _id: 1, score: 3 }, { _id: 3, score: 3 } ]
Both the documents receive the same score because the
constant
option in the query replaces the score of each
document in the result with the number 3
.
➤ Try this in the Atlas Search Playground.
minimumShouldMatch Example
In a query with multiple should
clauses, you can use the
miniumumShouldMatch
option to specify a minimum number of clauses
which must match to return a result.
The following query has one must
clause and two should
clauses,
with a minimumShouldMatch
value of 1
. A document must include
the term varieties
in the description
field and must include
either Fuji
or Golden Delicious
in the description field to be
included in the result set.
1 db.fruit.aggregate([ 2 { 3 $search: { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "Fuji", 14 "path": "description" 15 } 16 }, 17 { 18 "text": { 19 "query": "Golden Delicious", 20 "path": "description" 21 } 22 }], 23 "minimumShouldMatch": 1 24 } 25 } 26 } 27 ])
1 { 2 "_id" : 1, 3 "type" : "apple", 4 "description" : "Apples come in several varieties, including Fuji, Granny Smith, and Honeycrisp.", 5 "category" : "nonorganic", 6 "in_stock" : false 7 }
The document with _id: 1
matches the must
clause and the first
of the two should
clauses.
➤ Try this in the Atlas Search Playground.
filter
Examples
filter
behaves the same as must
, except that the filter
clause is not considered in a returned document's score, and therefore
does not affect the order of the returned documents.
The following query uses the following clauses:
must
andfilter
to specify search conditions which must be met.should
to specify preference for documents containing the wordbanana
. Theshould
clause doesn't include theminimumShouldMatch
option. When you omitminimumShouldMatch
, it defaults to0
.
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "must": [{ 6 "text": { 7 "query": "varieties", 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "banana", 14 "path": "description" 15 } 16 }], 17 "filter": [{ 18 "text": { 19 "query": "granny", 20 "path": "description" 21 } 22 }] 23 } 24 } 25 } 26 ])
1 { 2 "_id" : 1, 3 "type" : "apple", 4 "description" : "Apples come in several varieties, including Fuji, Granny Smith, and Honeycrisp.", 5 "category" : "nonorganic", 6 "in_stock" : false 7 }
The returned document fulfills all the requirements for inclusion:
Both the
must
clause and thefilter
clause match.The
minimumShouldMatch
value is not specified, so it defaults to0
. As a result, theshould
clause fails and still returns a document.
➤ Try this in the Atlas Search Playground.
You can replace the $match
with $in
in your
queries against data on your Atlas cluster with the
filter
clause. The following query demonstrates how to use
filter
in the $search
stage to specify the search
terms that must match. The query also uses should
to specify
preference for documents containing the term varieties
. The
query includes the $project
pipeline stage to do the
following:
Exclude all fields except
_id
anddescription
.Add a
score
field, which displays the document's relevance score.
1 db.fruit.aggregate([ 2 { 3 "$search": { 4 "compound": { 5 "filter": [{ 6 "text": { 7 "query": ["apples", "bananas"], 8 "path": "description" 9 } 10 }], 11 "should": [{ 12 "text": { 13 "query": "varieties", 14 "path": "description" 15 } 16 }] 17 } 18 } 19 }, 20 { 21 "$project": { 22 "description": 1, 23 "score": { "$meta": "searchScore" } 24 } 25 } 26 ])
1 [ 2 { 3 _id: 1, 4 description: 'Apples come in several varieties, including Fuji, Granny Smith, and Honeycrisp. The most popular varieties are McIntosh, Gala, and Granny Smith.', 5 score: 0.36074575781822205 6 }, 7 { 8 _id: 2, 9 description: 'Bananas are usually sold in bunches of five or six.', 10 score: 0 11 } 12 ]
The documents in the result fulfill all the requirements for inclusion:
Both documents contain the term
apples
orbananas
that was specified in thefilter
clause of the query.Document with
_id: 1
scores higher than document with_id: 2
because it contains the termvarieties
specified in theshould
clause of the query.
➤ Try this in the Atlas Search Playground.
Nested Example
The following example uses nested compound
clauses to construct a
query. For this example, the fruit
collection has an index on the
type
, category
, and in_stock
fields, whose text fields use the
default analyzer. The query requires
documents to only satisfy one of the following should
clauses:
Contain the word
apple
in thetype
field.Contain the term
organic
in thecategory
field and have the valuetrue
in thein_stock
field.
1 db.fruit.aggregate([ 2 { 3 $search: { 4 "compound": { 5 "should": [ 6 { 7 "text": { 8 "query": "apple", 9 "path": "type" 10 } 11 }, 12 { 13 "compound": { 14 "must": [ 15 { 16 "text": { 17 "query": "organic", 18 "path": "category" 19 } 20 }, 21 { 22 "equals": { 23 "value": true, 24 "path": "in_stock" 25 } 26 } 27 ] 28 } 29 } 30 ], 31 "minimumShouldMatch": 1 32 } 33 } 34 } 35 ])
1 { 2 "_id" : 3, 3 "type" : "pear", 4 "description" : "Bosc and Bartlett are the most common varieties of pears.", 5 "category" : "organic", 6 "in_stock" : true 7 } 8 { 9 "_id" : 1, 10 "type" : "apple", 11 "description" : "Apples come in several varieties, including Fuji, Granny Smith, and Honeycrisp.", 12 "category" : "nonorganic", 13 "in_stock" : false 14 }
The documents in the results fulfill all the requirements for inclusion:
The document with
_id: 3
matches themust
clause nested within the secondshould
clause.The document with
_id: 1
matches the firstshould
clause.
➤ Try this in the Atlas Search Playground.