Wildcard Indexes通配符索引

On this page本页内容

MongoDB supports creating indexes on a field or set of fields to support queries. MongoDB支持在字段或字段集上创建索引以支持查询。Since MongoDB supports dynamic schemas, applications can query against fields whose names cannot be known in advance or are arbitrary.由于MongoDB支持动态模式,应用程序可以查询名称无法预先知道或任意的字段。

New in version MongoDB:MongoDB中的新版本:4.2

MongoDB 4.2 introduces wildcard indexes for supporting queries against unknown or arbitrary fields.MongoDB 4.2引入了通配符索引,以支持对未知或任意字段的查询。

Consider an application that captures user-defined data under the userMetadata field and supports querying against that data:考虑一个在userMetadata字段下捕获用户定义数据的应用程序,并支持对该数据进行查询:

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

Administrators want to create indexes to support queries on any subfield of userMetadata.管理员希望创建索引以支持对userMetadata的任何子字段的查询。

A wildcard index on userMetadata can support single-field queries on userMetadata, userMetadata.likes, userMetadata.dislikes, and userMetadata.age:userMetadata上的通配符索引可以支持userMetadatauserMetadata.likesuserMetadata.dislikesuserMetadata.age上的单字段查询:

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

The index can support the following queries:该索引可以支持以下查询:

db.userData.find({ "userMetadata.likes" : "dogs" })
db.userData.find({ "userMetadata.dislikes" : "pickles" })
db.userData.find({ "userMetadata.age" : { $gt : 30 } })
db.userData.find({ "userMetadata" : "inactive" })

A non-wildcard index on userMetadata can only support queries on values of userMetadata.userMetadata上的非通配符索引只能支持对userMetadata值的查询。

Important重要的

Wildcard indexes are not designed to replace workload-based index planning. 通配符索引不是为了取代基于工作负载的索引规划而设计的。For more information on creating indexes to support queries, see Create Indexes to Support Your Queries. 有关创建索引以支持查询的更多信息,请参阅创建索引以支持查询For complete documentation on wildcard index limitations, see Wildcard Index Restrictions.有关通配符索引限制的完整文档,请参阅通配符索引限制

Create Wildcard Index创建通配符索引

Important重要的

The mongod featureCompatibilityVersion must be 4.2 to create wildcard indexes. mongod featureCompatibilityVersion必须为4.2才能创建通配符索引。For instructions on setting the fCV, see Set Feature Compatibility Version on MongoDB 4.4 Deployments.有关设置fCV的说明,请参阅在MongoDB 4.4部署上设置功能兼容性版本

You can create wildcard indexes using the createIndexes database command or its shell helpers, createIndex() or createIndexes().可以使用createIndexes数据库命令或其shell助手createIndex()createIndexes()创建通配符索引。

Create a Wildcard Index on a Field在字段上创建通配符索引

To index the value of a specific field:要索引特定字段的值,请执行以下操作:

db.collection.createIndex( { "fieldA.$**" : 1 } )

With this wildcard index, MongoDB indexes all values of fieldA. 通过这个通配符索引,MongoDB对fieldA的所有值进行索引。If the field is a nested document or array, the wildcard index recurses into the document/array and stores the value for all fields in the document/array.如果字段是嵌套文档或数组,则通配符索引将递归到文档/数组中,并存储文档/数组中所有字段的值。

For example, documents in the product_catalog collection may contain a product_attributes field. 例如,product_catalog集合中的文档可能包含product_attributes字段。The product_attributes field can contain arbitrary nested fields, including embedded documents and arrays:product_attributes字段可以包含任意嵌套字段,包括嵌入的文档和数组:

{
  "product_name" : "Spy Coat",
  "product_attributes" : {
    "material" : [ "Tweed", "Wool", "Leather" ]
    "size" : {
      "length" : 72,
      "units" : "inches"
    }
  }
}

{
  "product_name" : "Spy Pen",
  "product_attributes" : {
     "colors" : [ "Blue", "Black" ],
     "secret_feature" : {
       "name" : "laser",
       "power" : "1000",
       "units" : "watts",
     }
  }
}

The following operation creates a wildcard index on the product_attributes field:以下操作在product_attributes字段上创建通配符索引:

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

The wildcard index can support arbitrary single-field queries on product_attributes or its embedded fields:通配符索引可以支持对product_attributes或其嵌入字段的任意单字段查询:

db.products_catalog.find( { "product_attributes.size.length" : { $gt : 60 } } )
db.products_catalog.find( { "product_attributes.material" : "Leather" } )
db.products_catalog.find( { "product_attributes.secret_feature.name" : "laser" } )

Note

The path-specific wildcard index syntax is incompatible with the wildcardProjection option. 路径特定的通配符索引语法与wildcardProjection选项不兼容。See the Options for wildcard indexes for more information.有关更多信息,请参阅通配符索引选项

For an example, see Create a Wildcard Index on a Single Field Path.有关示例,请参阅在单个字段路径上创建通配符索引

Create a Wildcard Index on All Fields在所有字段上创建通配符索引

To index the value of all fields in a document (excluding _id), specify "$**" as the index key:要索引文档中所有字段的值(不包括_id),请指定"$**"作为索引键:

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

With this wildcard index, MongoDB indexes all fields for each document in the collection. 通过这个通配符索引,MongoDB为集合中每个文档的所有字段编制索引。If a given field is a nested document or array, the wildcard index recurses into the document/array and stores the value for all fields in the document/array.如果给定字段是嵌套文档或数组,则通配符索引将递归到文档/数组中,并存储文档/数组中所有字段的值。

For an example, see Create a Wildcard Index on All Field Paths.例如,请参阅在所有字段路径上创建通配符索引

Note

Wildcard indexes omit the _id field by default. 默认情况下,通配符索引会忽略_id字段。To include the _id field in the wildcard index, you must explicitly include it in the wildcardProjection document. 要在通配符索引中包含_id字段,必须在wildcardProjection文档中显式包含它。See Options for wildcard indexes for more information.有关更多信息,请参阅通配符索引选项

Create a Wildcard Index on Multiple Specific Fields在多个特定字段上创建通配符索引

To index the values of multiple specific fields in a document:要为文档中多个特定字段的值编制索引,请执行以下操作:

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

With this wildcard index, MongoDB indexes all values for the specified fields for each document in the collection. 使用此通配符索引,MongoDB为集合中每个文档的指定字段的所有值编制索引。If a given field is a nested document or array, the wildcard index recurses into the document/array and stores the value for all fields in the document/array.如果给定字段是嵌套文档或数组,则通配符索引将递归到文档/数组中,并存储文档/数组中所有字段的值。

Note

Wildcard indexes do not support mixing inclusion and exclusion statements in the wildcardProjection document except when explicitly including the _id field. 通配符索引不支持在wildcardProjection文档中混合包含和排除语句,除非显式包含_id字段。For more information on wildcardProjection, see the Options for wildcard indexes.有关wildcardProjection的更多信息,请参阅通配符索引的选项

For an example, see Include Specific Fields in Wildcard Index Coverage.例如,请参阅在通配符索引覆盖范围中包含特定字段

Create a Wildcard Index that Excludes Multiple Specific Fields创建排除多个特定字段的通配符索引

To index the fields of all fields in a document excluding specific field paths:要索引文档中所有字段(排除特定字段路径)的字段,请执行以下操作:

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

With this wildcard index, MongoDB indexes all fields for each document in the collection excluding the specified field paths. 通过这个通配符索引,MongoDB为集合中每个文档的所有字段编制索引,排除指定的字段路径。If a given field is a nested document or array, the wildcard index recurses into the document/array and stores the values for all fields in the document/array.如果给定字段是嵌套文档或数组,则通配符索引将递归到文档/数组中,并存储文档/数组中所有字段的值。

For an example, see Omit Specific Fields from Wildcard Index Coverage.例如,请参阅从通配符索引覆盖范围中忽略特定字段

Note

Wildcard indexes do not support mixing inclusion and exclusion statements in the wildcardProjection document except when explicitly including the _id field. 通配符索引不支持在wildcardProjection文档中混合包含和排除语句,除非显式包含_id字段。For more information on wildcardProjection, see the Options for wildcard indexes.有关wildcardProjection的更多信息,请参阅通配符索引的选项

Considerations考虑事项

Behavior行为

Wildcard indexes have specific behavior when indexing fields which are an object (i.e. an embedded document) or an array:在为对象(即嵌入文档)或数组字段编制索引时,通配符索引具有特定的行为:

The wildcard index continues traversing any additional nested objects or arrays until it reaches a primitive value (i.e. a field that is not an object or array). 通配符索引将继续遍历任何其他嵌套对象或数组,直到达到基本值(即不是对象或数组的字段)。It then indexes this primitive value, along with the full path to that field.然后,它对该原语值以及该字段的完整路径进行索引。

For example, consider the following document:例如,考虑以下文件:

{
  "parentField" : {
    "nestedField" : "nestedValue",
    "nestedObject" : {
      "deeplyNestedField" : "deeplyNestedValue"
    },
    "nestedArray" : [
      "nestedArrayElementOne",
      [ "nestedArrayElementTwo" ]
    ]
  }
}

A wildcard index which includes parentField records the following entries:包含parentField的通配符索引记录以下条目:

Note that the records for parentField.nestedArray do not include the array position for each element. 请注意,parentField.nestedArray的记录不包括每个元素的数组位置。Wildcard indexes ignore array element positions when recording the element into the index. 在将元素记录到索引中时,通配符索引会忽略数组元素的位置。Wildcard indexes can still support queries that include explicit array indices. 通配符索引仍然可以支持包含显式数组索引的查询。See Queries with Explicit Array Indices for more information.有关详细信息,请参阅带有显式数组索引的查询

For more information on wildcard index behavior with nested objects, see Nested Objects.有关嵌套对象的通配符索引行为的详细信息,请参阅嵌套对象

For more information on wildcard index behavior with nested arrays, see Nested Arrays.有关嵌套数组的通配符索引行为的详细信息,请参阅嵌套数组

Nested Objects嵌套对象

When a wildcard index encounters a nested object, it descends into the object and indexes its contents. 当通配符索引遇到嵌套对象时,它会下降到该对象中并对其内容编制索引。For example:例如:

{
  "parentField" : {
    "nestedField" : "nestedValue",
    "nestedArray" : ["nestedElement"]
    "nestedObject" : {
      "deeplyNestedField" : "deeplyNestedValue"
    }
  }
}

A wildcard index which includes parentField descends into the object to traverse and index its contents:包含parentField的通配符索引会下降到对象中,以遍历和索引其内容:

  • For each field which is itself an object (i.e. an embedded document), descend into the object to index its contents.对于本身是对象(即嵌入式文档)的每个字段,深入对象以索引其内容。
  • For each field which is an array, traverse the array and index its contents.对于数组中的每个字段,遍历数组并为其内容编制索引。
  • For all other fields, record the primitive (non-object/array) value into the index.对于所有其他字段,将基元(非对象/数组)值记录到索引中。

The wildcard index continues traversing any additional nested objects or arrays until it reaches a primitive value (i.e. a field that is not an object or array). 通配符索引将继续遍历任何其他嵌套对象或数组,直到达到基本值(即不是对象或数组的字段)。It then indexes this primitive value, along with the full path to that field.然后,它对该原语值以及该字段的完整路径进行索引。

Given the sample document, the wildcard index adds the following records to the index:给定示例文档,通配符索引将以下记录添加到索引中:

  • "parentField.nestedField" : "nestedValue"
  • "parentField.nestedObject.deeplyNestedField" : "deeplyNestedValue"
  • "parentField.nestedArray" : "nestedElement"

For more information on wildcard index behavior with nested arrays, see Nested Arrays.有关嵌套数组的通配符索引行为的详细信息,请参阅嵌套数组

Nested Arrays嵌套数组

When a wildcard index encounters a nested array, it attempts to traverse the array to index its elements. 当通配符索引遇到嵌套数组时,它会尝试遍历该数组以索引其元素。If the array is itself an element in a parent array (i.e. an embedded array), the wildcard index instead records the entire array as a value instead of traversing its contents. 如果数组本身是父数组(即嵌入式数组)中的一个元素,则通配符索引会将整个数组记录为一个值,而不是遍历其内容。For example:例如:

{
  "parentArray" : [
    "arrayElementOne",
    [ "embeddedArrayElement" ],
    "nestedObject" : {
      "nestedArray" : [
        "nestedArrayElementOne",
        "nestedArrayElementTwo"
      ]
    }
  ]
}

A wildcard index which includes parentArray descends into the array to traverse and index its contents:包含parentArray的通配符索引会下降到数组中,以遍历和索引其内容:

  • For each element which is an array (i.e. an embedded array), index the entire array as a value.对于作为数组(即嵌入式数组)的每个元素,将整个数组作为一个值进行索引。
  • For each element which is an object, descend into the object to traverse and index its contents.对于作为对象的每个元素,深入到对象中遍历并索引其内容。
  • For all other fields, record the primitive (non-object/array) value into the index.对于所有其他字段,将基元(非对象/数组)值记录到索引中。

The wildcard index continues traversing any additional nested objects or arrays until it reaches a primitive value (i.e. a field that is not an object or array). 通配符索引将继续遍历任何其他嵌套对象或数组,直到达到基本值(即不是对象或数组的字段)。It then indexes this primitive value, along with the full path to that field.然后,它对该原语值以及该字段的完整路径进行索引。

Given the sample document, the wildcard index adds the following records to the index:给定示例文档,通配符索引将以下记录添加到索引中:

  • "parentArray" : "arrayElementOne"
  • "parentArray" : ["embeddedArrayElement"]
  • "parentArray.nestedObject.nestedArray" : "nestedArrayElementOne"
  • "parentArray.nestedObject.nestedArray" : "nestedArrayElementTwo"

Note that the records for parentField.nestedArray do not include the array position for each element. 请注意,parentField.nestedArray的记录不包括每个元素的数组位置。Wildcard indexes ignore array element positions when recording the element into the index. 在将元素记录到索引中时,通配符索引会忽略数组元素的位置。Wildcard indexes can still support queries that include explicit array indices. 通配符索引仍然可以支持包含显式数组索引的查询。See Queries with Explicit Array Indices for more information.有关详细信息,请参阅带有显式数组索引的查询

Restrictions限制

Important

Wildcard Indexes are distinct from and incompatible with Wildcard Text Indexes. 通配符索引不同于通配符文本索引,并且与通配符文本索引不兼容。Wildcard indexes cannot support queries using the $text operator.通配符索引无法支持使用$text运算符的查询。

For complete documentation on wildcard index creation restrictions, see Incompatible Index Types or Properties.有关通配符索引创建限制的完整文档,请参阅不兼容索引类型或属性

Wildcard Index Query/Sort Support通配符索引查询/排序支持

Covered Queries覆盖查询

Wildcard indexes can support a covered query only if all of the following are true:通配符索引仅在满足以下所有条件时才支持覆盖查询

  • The query planner selects the wildcard index for satisfying the query predicate.查询计划器选择通配符索引以满足查询谓词。
  • The query predicate specifies exactly one field covered by the wildcard index.查询谓词只指定通配符索引覆盖的一个字段。
  • The projection explicitly excludes _id and includes only the query field.投影显式排除_id,只包括查询字段。
  • The specified query field is never an array.指定的查询字段永远不是数组。

Consider the following wildcard index on the employees collection:考虑employees集合上的下列通配符索引:

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

The following operation queries for a single field lastName and projects out all other fields from the resulting document:以下操作查询单个字段lastName,并从结果文档中投影出所有其他字段:

db.products.find(
  { "lastName" : "Doe" },
  { "_id" : 0, "lastName" : 1 }
)

Assuming that the specified lastName is never an array, MongoDB can use the $** wildcard index for supporting a covered query.假设指定的lastName永远不是数组,MongoDB可以使用$**通配符索引来支持覆盖查询。

Multi-Field Query Predicates多字段查询谓词

Wildcard indexes can support at most one query predicate field. 通配符索引最多支持一个查询谓词字段。That is:也就是说:

  • MongoDB cannot use a non-wildcard index to satisfy one part of a query predicate and a wildcard index to satisfy another.MongoDB不能使用非通配符索引来满足查询谓词的一部分,而使用通配符索引来满足另一部分。
  • MongoDB cannot use one wildcard index to satisfy one part of a query predicate and another wildcard index to satisfy another.MongoDB不能使用一个通配符索引来满足查询谓词的一部分,而使用另一个通配符索引来满足另一部分。
  • Even if a single wildcard index could support multiple query fields, MongoDB can use the wildcard index to support only one of the query fields.即使单个通配符索引可以支持多个查询字段,MongoDB也可以使用通配符索引只支持一个查询字段。 All remaining fields are resolved without an index.所有剩余字段都将在没有索引的情况下解析。

However, MongoDB may use the same wildcard index for satisfying each independent argument of the query $or or aggregation $or operators.但是,MongoDB可以使用相同的通配符索引来满足查询$or或聚合$or运算符的每个独立参数。

Queries with Sort带排序的查询

MongoDB can use a wildcard index for satisfying the sort() only if all of the following are true:只有在满足以下所有条件时,MongoDB才能使用通配符索引来满足sort()

  • The query planner selects the wildcard index for satisfying the query predicate.查询计划器选择通配符索引以满足查询谓词。
  • The sort() specifies only the query predicate field.sort()只指定查询谓词字段。
  • The specified field is never an array.指定的字段永远不是数组。

If the above conditions are not met, MongoDB cannot use the wildcard index for the sort. 如果不满足上述条件,MongoDB将无法使用通配符索引进行排序。MongoDB does not support sort operations that require a different index from that of the query predicate. MongoDB不支持需要与查询谓词索引不同的索引的sort操作。For more information, see Index Intersection and Sort.有关详细信息,请参阅索引交点和排序

Consider the following wildcard index on the products collection:考虑products集合上的下列通配符索引:

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

The following operation queries for a single field product_attributes.price and sorts on that same field:以下操作查询单个字段的product_attributes.price并对同一字段排序:

db.products.find(
  { "product_attributes.price" : { $gt : 10.00 } },
).sort(
  { "product_attributes.price" : 1 }
)

Assuming that the specified price is never an array, MongoDB can use the product_attributes.$** wildcard index for satisfying both the find() and sort().假设指定的price永远不是数组,MongoDB可以使用product_attributes.$**通配符索引用于同时满足find()sort()

Unsupported Query Patterns不支持的查询模式

  • Wildcard indexes cannot support query condition that checks if a field does not exist.通配符索引不支持检查字段是否不存在的查询条件。
  • Wildcard indexes cannot support query condition that checks if a field is or is not equal to a document or an array通配符索引不支持检查字段是否等于文档或数组的查询条件
  • Wildcard indexes cannot support query condition that checks if a field is not equal to null.通配符索引不能支持检查字段是否不等于null的查询条件。

For details, see Unsupported Query and Aggregation Patterns.有关详细信息,请参阅不支持的查询和聚合模式

Queries with Explicit Array Indices具有显式数组索引的查询

MongoDB wildcard indexes do not record the array position of any given element in an array during indexing. However, MongoDB may still select the wildcard index to answer a query which includes a field path with one or more explicit array indices (for example, parentArray.0.nestedArray.0). 在索引期间,MongoDB通配符索引不会记录数组中任何给定元素的数组位置。但是,MongoDB仍然可以选择通配符索引来回答包含具有一个或多个显式数组索引的字段路径的查询(例如,parentArray.0.nestedArray.0)。Due to the increasing complexity of defining index bounds for each consecutive nested array, MongoDB does not consider the wildcard index to answer a given field path in the query if that path contains more than 8 explicit array indices. 由于定义了每个连续嵌套数组的索引界限的日益复杂,如果该路径包含超过8个显式数组索引,MunGDB不考虑通配符索引来回答查询中的给定字段路径。MongoDB can still consider the wildcard index to answer other field paths in the query.MunGDB仍然可以考虑通配符索引来回答查询中的其他字段路径。

For example:例如:

{
  "parentObject" : {
    "nestedArray" : [
       "elementOne",
       {
         "deeplyNestedArray" : [ "elementTwo" ]
       }
     ]
  }
}

MongoDB can select a wildcard index which includes parentObject to satisfy the following queries:MongoDB可以选择包含parentObject的通配符索引,以满足以下查询:

  • "parentObject.nestedArray.0" : "elementOne"
  • "parentObject.nestedArray.1.deeplyNestedArray.0" : "elementTwo"

If a given field path in the query predicate specifies more than 8 explicit array indices, MongoDB does not consider the wildcard index for answering that field path. MongoDB instead either selects another eligible index to answer the query, or performs a collection scan.如果查询谓词中的给定字段路径指定了超过8个显式数组索引,则MunGDB不考虑通配符索引来回答该字段路径。MongoDB要么选择另一个符合条件的索引来回答查询,要么执行集合扫描。

Note that wildcard indexes themselves do not have any 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. 请注意,通配符索引本身对索引文档时遍历文档的深度没有任何限制;该限制仅适用于显式指定精确数组索引的查询。By issuing the same queries without the explicit array indices, MongoDB may select the wildcard index to answer the query:通过发出没有显式数组索引的相同查询,MongoDB可以选择通配符索引来回答查询:

  • "parentObject.nestedArray" : "elementOne"
  • "parentObject.nestedArray.deeplyNestedArray" : "elementTwo"