Wildcard Indexes on Embedded Objects and Arrays
Wildcard indexes have specific behavior when indexing embedded object and array fields:
If the field is an object, the wildcard index descends into the object and indexes its contents. The wildcard index continues descending into any additional embedded documents it encounters.
If the field is an array, the wildcard index traverses the array and indexes each element:
If the element is an object, the wildcard index descends into the object to index its contents.
If the element is an array (that is, an array which is embedded directly within the parent array), the wildcard index does not traverse the embedded array, but indexes the entire array as a single value.
For all other fields, the index stores the primitive value. A primitive value is a non-object, non-array value.
The wildcard index continues traversing any additional embedded objects or arrays until it reaches a primitive value. It then indexes the primitive value, along with the full path to that field.
Wildcard Indexes on Embedded Objects
When a wildcard index encounters an embedded object, it descends into the object and indexes its contents. For example, consider this document:
db.users.insertOne( { account: { username: "SuperAdmin01", contact: { phone: "123-456-7890", email: "xyz@example.com" }, access: { group: "admin" } } } )
A wildcard index that includes the account
field descends into the
account
object to traverse and index its contents:
For each subfield which is itself an object (for example,
account.contact
andaccount.access
), the index descends into the object and records its contents.For all other subfields, the index records the primitive value into the index.
Given the sample document, the wildcard index adds the following records to the index:
"account.username" : "SuperAdmin01"
"account.contact.phone" : "123-456-7890"
"account.contact.email" : "xyz@example.com"
"account.access.group" : "admin"
Wildcard Indexes on Arrays
When a wildcard index encounters an array, it traverses the array to index its elements. If the array element is itself an array (an embedded array), the index records the entire embedded array as a value instead of traversing its contents.
For example, consider this document:
db.fleet.insertOne( { "ship": { "coordinates" : [ [-5, 10], [-7, 8] ], "type": "Cargo Ship", "captains": [ { "name": "Francis Drake", "crew": [ "first mate", "carpenter" ] } ] } } )
A wildcard index which includes the ship
field descends into the
object to traverse and index its contents:
For each element which is an array:
If the element is itself an array (as in an embedded array), the index records the entire array as a value.
If the element is an object, the index descends into the object to traverse and index its contents.
If the element is a primitive value, the index records that value.
For non-array, non-object fields, the index records the primitive value into the index.
Given the sample document, the wildcard index adds the following records to the index:
"ship.coordinates" : [-5, 10]
"ship.coordinates" : [-7, 8]
"ship.type" : "Cargo Ship"
"ship.captains.name" : "Francis Drake"
"ship.captains.crew" : "first mate"
"ship.captains.crew" : "carpenter"
Queries with Explicit Array Indices
Wildcard indexes do not record the array position of any given element in an array during indexing. However, MongoDB may still use the wildcard index to fulfill a query that includes a field path with one or more explicit array indices.
For example, consider this document:
db.fleet.insertOne( { "ship": { "coordinates" : [ [-5, 10], [-7, 8] ], "type": "Cargo Ship", "captains": [ { "name": "Francis Drake", "crew": [ "first mate", "carpenter" ] } ] } } )
Create a wildcard index that includes the ship
field:
db.fleet.createIndex( { "ship.$**": 1 } )
The index records for ship.coordinates
and ship.captains
do not
include the array position for each element. Wildcard indexes ignore
array element positions when recording the element into the index.
However, wildcard indexes can still support queries that include
explicit array indices.
MongoDB can use the wildcard index to fulfill this query:
db.fleet.find( { "ship.captains.0.name": "Francis Drake" } )
The query returns the sample document:
[ { _id: ObjectId("6350537db1fac2ee2e957efc"), ship: { coordinates: [ [ -5, 10 ], [ -7, 8 ] ], type: 'Cargo Ship', captains: [ { name: 'Francis Drake', crew: [ 'first mate', 'carpenter' ] } ] } } ]
MongoDB cannot use the wildcard index to fulfill this query:
db.fleet.find( { "ship.coordinates.0.1": 10 } )
The ship.coordinates
field contains embedded arrays. Wildcard
indexes do not record individual values of embedded arrays. Instead,
they record the entire embedded array. As a result, the wildcard index
cannot support a match on an embedded array value, and MongoDB fulfills
the query with a collection scan.
Array Index Limitation
MongoDB can only use a wildcard index to fulfill a given field path in the query if the path contains 8 or fewer explicit array indices. If the field path contains more than 8 explicit indices, to fulfill the query, MongoDB either:
Selects another eligible index.
Performs a collection scan.
Wildcard indexes themselves do not have limits on the depth to which they traverse a document while indexing it. The limitation only applies to queries which explicitly specify exact array indices.