Usage examples for the MongoDB wildcard index

  • 2021-01-18 06:45:00
  • OfStack

guide

Wildcard Indexes is released in version 4.2. This article provides a brief overview of what Wildcard Indexes is and what scenarios Wildcard Indexes is suitable for, combined with official documentation and actual testing.

Example wildcard index

Because MongoDB is dynamic schemas, applications can query any known field or random field.

Assume (this hypothetical example is taken from the official documentation) that the UserMetadata field of the collection colA contains the following data:


{ "userMetadata" : { "likes" : [ "dogs", "cats" ] } }
{ "userMetadata" : { "dislikes" : "pickles" } }
{ "userMetadata" : { "age" : 45 } }
{ "userMetadata" : "inactive" }

When querying, however, it might look like this:


db.colA.find({ "userMeta2
 The form of a wildcard index data.likes" : "dogs" })
db.colA.find({ "userMetadata.dislikes" : "pickles" })
db.colA.find({ "userMetadata.age" : { $gt : 30 } })
db.colA.find({ "userMetadata" : "inactive" })

Is it possible to fulfill the above requirement with one index?

db.colA.createIndex ({" userMetadata.$**" : 1}); db.colA.createIndex ({" userMetadata.$**" : 1});

So how do you create a wildcard index?

Note: The first thing to make clear is that wildcard indexes can only be created with version compatibility 4.2.

How do I query version compatibility?


db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

How to set it?


db.adminCommand( { setFeatureCompatibilityVersion: "4.2" } )

2. The form of wildcard index

Single field wildcard index


{
 "_id" : ObjectId("5ee2df16911d8dfaa91520b4"),
 "product_name" : "Spy Coat",
 "product_attributes" : {
 "material" : [
 "Tweed",
 "Wool",
 "Leather"
 ],
 "size" : {
 "length" : 72,
 "units" : "inches"
 }
 }
}
{
 "_id" : ObjectId("5ee2df30911d8dfaa91520b5"),
 "product_name" : "Spy Pen",
 "product_attributes" : {
 "colors" : [
 "Blue",
 "Black"
 ],
 "secret_feature" : {
 "name" : "laser",
 "power" : "1000",
 "units" : "watts"
 }
 }
}
[

If the data structure looks like the above, the product_attributes attribute contains any structure.

So if we create one of these indexes, what does it do?

db. product_catalog. createIndex ({" product_attributes. $* * ": 1}).

Because product_attributes contains objects such as arrays and nested documents, the actual creation of the index will iterate through the nested documents or arrays to get all the values out of them into the index. The following queries are supported:

]

db.product_catalog.find({"product_attributes.colors":"Blue"})
db.product_catalog.find({"product_attributes.secret_feature.name":"laser"})
db.product_catalog.find({"product_attributes.size.length":{$gt:60}})

Wildcard index for the full field

You can create an index that contains all the fields in the collection but not _id (if you want to include _id you can use wildcardProjection). If the fields in the collection contain arrays or nested objects, then iterate over the array or nested objects and place the values in the index.


Db.product_catalog.createIndex({ " $** " :1}) 

Add 1 address field to each document.


7777:PRIMARY> db.product_catalog.find().pretty()
{
 "_id" : ObjectId("5ee2df16911d8dfaa91520b4"),
 "product_name" : "Spy Coat",
 "product_attributes" : {
 "material" : [
 "Tweed",
 "Wool",
 "Leather"
 ],
 "size" : {
 "length" : 72,
 "units" : "inches"
 }
 },
 "address" : "Beijing"
}
{
 "_id" : ObjectId("5ee2df30911d8dfaa91520b5"),
 "product_name" : "Spy Pen",
 "product_attributes" : {
 "colors" : [
 "Blue",
 "Black"
 ],
 "secret_feature" : {
 "name" : "laser",
 "power" : "1000",
 "units" : "watts"
 }
 },
 "address" : "Tianjin"
}

db.product_catalog.find({"product_name":"Spy Coat","address":"nanji","product_attributes.colors":"Blue"})

It is possible to specify which fields to include or not include in a wildcard index based on a full-field wildcard index, but only on a single-field wildcard index:

Create an index that specifies which fields to include from the full field:


db.collection.createIndex(
 { "$**" : 1 },
 { "wildcardProjection" :
 { "fieldA" : 1, "fieldB.fieldC" : 1 }
 }
)

Note: Wildcard indexes do not support mixing include and exclude statements when using wildcardProjection, except when the _id field is explicitly specified.

Create an index with all fields specified in the index:


db.collection.createIndex(
 { "$**" : 1 },
 { "wildcardProjection" :
 { "fieldA" : 0, "fieldB.fieldC" : 0 }
 }
)

3. Behavior of wildcard indexes

Wildcard indexes behave differently depending on their field type.

Fields are objects
In the case of an object, the contents of the object are stored in the index, and the wildcard index loads all nested objects in the object into the index. The field is an array
In the case of an array, the wildcard index traverses the array and stores each element in the index.
If the element in the array is an object, the wildcard index loads the contents of the object into the index, just as loading object 1 did above.
The wildcard index does not iterate over the nested array if the elements in the array are one array (which is a multidimensional array). Instead, the entire nested array is viewed as a single value. Other types of
Log the value into an array.
The wildcard index will continue to iterate over any nested object or array up to the bottom level (that is, not before iterating), and then it will index the full path.

Wildcard index for a query that displays the array position

Although wildcard indexes do not record the subscripts of elements in a given array, MongoDB can still select wildcard indexes to satisfy queries that contain the path of one or more explicit array indexes (for example, parentArray.0.nestedArray.0).

Due to the increasing complexity of defining index boundaries for each contiguous nested array, if the path contains more than eight explicit array indexes, MongoDB does not consider using wildcard indexes to answer a given field path in a query. MongoDB can still consider using wildcard indexes to answer other field paths in the query.

If more than 8 indexes are displayed, MongoDB will consider another index or perform a full set scan. The following structure:


db.colA.find({ "userMeta2
 The form of a wildcard index data.likes" : "dogs" })
db.colA.find({ "userMetadata.dislikes" : "pickles" })
db.colA.find({ "userMetadata.age" : { $gt : 30 } })
db.colA.find({ "userMetadata" : "inactive" })
0

Note that the wildcard index itself has no limit on how far a document can be traversed when indexing a document; This restriction applies only to queries that explicitly specify the exact array index. By issuing the same query without an explicit array index, MongoDB can select a wildcard index to answer the query.

4. Restrictions on wildcard indexes

1. First of all, wildcard index is a sparse index. Only existing fields are stored in the index, and non-existing fields are not stored, that is to say, when you use {$exists:false}, you will not go to the index.

db.test_new_wildidx.find({"block.attr":{$exists:false}})

db.test_new_wildidx.find({"block.attr":{$exists:true}}) does not support true.

2. Wildcard indexes do not support directly equal to/not equal to 1 object or array.

Wildcard indexes load the elements of an object or array into the index, rather than putting them in the index as a whole. So wildcard indexes do not support matching directly with documents or arrays.

So the example above is if


db.colA.find({ "userMeta2
 The form of a wildcard index data.likes" : "dogs" })
db.colA.find({ "userMetadata.dislikes" : "pickles" })
db.colA.find({ "userMetadata.age" : { $gt : 30 } })
db.colA.find({ "userMetadata" : "inactive" })
1

If you want to match an entire array, you can't use a wildcard index.

So if there is a need how to address it? Db.test_new_wildidx.createIndex({"block.attr.address_new":1}) is resolved by this index.

Wildcard indexing does not allow an exact matching query for an entire document or object, but does allow null {} operations for arrays or objects:


db.colA.find({ "userMeta2
 The form of a wildcard index data.likes" : "dogs" })
db.colA.find({ "userMetadata.dislikes" : "pickles" })
db.colA.find({ "userMetadata.age" : { $gt : 30 } })
db.colA.find({ "userMetadata" : "inactive" })
2

Wildcard indexes support the following index types or attributes:

[

Compound
TTL
Text
2d (Geospatial)
2dsphere (Geospatial)
Hashed
Unique

]

4. The wildcard index does not support an array like $ne in a document. $ne does not use a wildcard index for any other field.

5, summary

Wildcard index in 1 degree can deal with at the beginning of the modeling for missing indexes to establish negligence, but if 1 flavour is dependent on the wildcard index to solve all kinds of precision fields in query matching is that people buy the shoe, zheng wildcards in the actual test indexes and accurate field index compared with the data of growth efficiency decline gradually. This is why it is not recommended to use wildcard indexes instead of regular indexes.


Related articles: