Multikey Indexes

在本页面

为了索引包含数组值的字段,MongoDB 为数组中的每个元素创建一个索引键。这些* multikey *索引支持对数组字段的高效查询。可以在同时保存标量值[1](例如字符串,数字)和嵌套文档的数组上构造多键索引。

addr.zip 字段上的多键索引图。 addr 字段包含地址文档的数组。地址文档包含``zip''字段。

[1]标量值是指既不是嵌入式文档也不是数组的值。

创建多键索引

要创建多键索引,请使用db.collection.createIndex()方法:

db.coll.createIndex( { <field>: < 1 or -1 > } )

如果任何索引字段是数组,MongoDB 都会自动创建一个多键索引;您无需显式指定多键类型。

在版本 3.4 中更改:仅适用于 WiredTiger 和内存中存储引擎

从 MongoDB 3.4 开始,对于使用 MongoDB 3.4 或更高版本创建的多键索引,MongoDB 会跟踪哪个索引字段或哪些字段导致索引成为多键索引。跟踪此信息使 MongoDB 查询引擎可以使用更严格的索引范围。

Index Bounds

如果索引是多键,则索引边界的计算遵循特殊规则。有关多键索引范围的详细信息,请参见多键索引范围

唯一多键索引

对于unique索引,唯一约束适用于集合中的各个文档,而不是单个文档。

因为唯一约束适用于单独的文档,所以对于唯一多键索引,文档可能具有导致重复索引键值的数组元素,只要该文档的索引键值不与另一个文档的索引键值重复即可。

有关更多信息,请参见跨单独文档的唯一约束

Limitations

复合多键索引

对于compound多键索引,每个索引文档最多可以有一个索引字段,该索引字段的值是一个数组。那是:

  • 如果文档的一个以上要索引的字段是一个数组,则无法创建复合多键索引。例如,考虑一个包含以下文档的集合:
{ _id: 1, a: [ 1, 2 ], b: [ 1, 2 ], category: "AB - both arrays" }

您无法在集合上创建复合多键索引{ a: 1, b: 1 },因为ab字段都是数组。

  • 或者,如果已经存在复合多键索引,则不能插入违反此限制的文档。

考虑一个包含以下文档的集合:

{ _id: 1, a: [1, 2], b: 1, category: "A array" }
{ _id: 2, a: 1, b: [1, 2], category: "B array" }

复合多键索引{ a: 1, b: 1 }是允许的,因为对于每个文档,仅由复合多键索引索引的一个字段是一个数组;即没有文档同时包含ab字段的数组值。

但是,在创建复合多键索引之后,如果您尝试插入ab字段均为数组的文档,则 MongoDB 将无法插入。

如果字段是文档数组,则可以为嵌入的字段构建索引以创建复合索引。例如,考虑一个包含以下文档的集合:

{ _id: 1, a: [ { x: 5, z: [ 1, 2 ] }, { z: [ 1, 2 ] } ] }
{ _id: 2, a: [ { x: 5 }, { z: 4 } ] }

您可以在{ "a.x": 1, "a.z": 1 }上创建复合索引。 最多一个索引字段可以是数组的限制也适用。

有关示例,请参见带有嵌入式文档的索引数组

Sorting

由于 MongoDB 3.6 中对数组字段的排序行为发生了更改,因此在对以multikey index索引的数组上进行排序时,查询计划包括一个阻塞的 SORT 阶段。新的排序行为可能会对性能产生负面影响。

在阻塞式 SORT 中,必须在排序步骤中使用所有 Importing,然后才能产生输出。在非阻塞或“索引”排序中,排序步骤扫描索引以按请求的 Sequences 产生结果。

Shard Keys

您不能**指定多键索引作为分片键索引。

但是,如果分片键索引是复合索引的prefix,则如果其他键之一(即不属于分片键的键)对数组进行索引,则允许复合索引成为复合* multikey *索引。复合多键索引可能会影响性能。

Hashed Indexes

Hashed索引“不能”为多键。

Covered Queries

Multikey indexes无法涵盖对数组字段的查询。

但是,从 3.6 开始,如果索引跟踪哪个或哪些字段导致索引成为多键,则多键索引可以覆盖非数组字段的查询。在 MongoDB 3.4 或更高版本中在 MMAPv1 以外的存储引擎上创建的多键索引会跟踪此数据。

整体查询数组字段

当查询过滤器指定整个数组的完全匹配时,MongoDB 可以使用多键索引来查找查询数组的第一个元素,但是不能使用多键索引扫描来查找整个数组。相反,在使用多键索引查找查询数组的第一个元素之后,MongoDB 检索关联的文档并过滤其数组与查询中的数组匹配的文档。

例如,考虑一个包含以下文档的inventory集合:

{ _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] }
{ _id: 6, type: "food", item: "bbb", ratings: [ 5, 9 ] }
{ _id: 7, type: "food", item: "ccc", ratings: [ 9, 5, 8 ] }
{ _id: 8, type: "food", item: "ddd", ratings: [ 9, 5 ] }
{ _id: 9, type: "food", item: "eee", ratings: [ 5, 9, 5 ] }

该集合在ratings字段上具有一个多键索引:

db.inventory.createIndex( { ratings: 1 } )

以下查询查找ratings字段为数组[ 5, 9 ]的文档:

db.inventory.find( { ratings: [ 5, 9 ] } )

MongoDB 可以使用多键索引来查找在ratings数组中任何位置具有5的文档。然后,MongoDB 检索这些文档并过滤ratings数组等于查询数组[ 5, 9 ]的文档。

Examples

索引基本数组

考虑包含以下文档的survey集合:

{ _id: 1, item: "ABC", ratings: [ 2, 5, 9 ] }

在字段ratings上创建索引:

db.survey.createIndex( { ratings: 1 } )

由于ratings字段包含一个数组,因此ratings上的索引是多键。多键索引包含以下三个索引键,每个都指向同一文档:

  • 2 ,

  • 5,以及

  • 9 .

具有嵌入式文档的索引数组

您可以在包含嵌套对象的数组字段上创建多键索引。

考虑包含以下格式文档的inventory集合:

{
  _id: 1,
  item: "abc",
  stock: [
    { size: "S", color: "red", quantity: 25 },
    { size: "S", color: "blue", quantity: 10 },
    { size: "M", color: "blue", quantity: 50 }
  ]
}
{
  _id: 2,
  item: "def",
  stock: [
    { size: "S", color: "blue", quantity: 20 },
    { size: "M", color: "blue", quantity: 5 },
    { size: "M", color: "black", quantity: 10 },
    { size: "L", color: "red", quantity: 2 }
  ]
}
{
  _id: 3,
  item: "ijk",
  stock: [
    { size: "M", color: "blue", quantity: 15 },
    { size: "L", color: "blue", quantity: 100 },
    { size: "L", color: "red", quantity: 25 }
  ]
}

...

以下操作在stock.sizestock.quantity字段上创建一个多键索引:

db.inventory.createIndex( { "stock.size": 1, "stock.quantity": 1 } )

复合多键索引可以支持包含既包含索引字段又包含仅包含索引前缀"stock.size"的谓词的查询,如以下示例所示:

db.inventory.find( { "stock.size": "M" } )
db.inventory.find( { "stock.size": "S", "stock.quantity": { $gt: 20 } } )

有关 MongoDB 如何组合多键索引范围的详细信息,请参阅多键索引范围。有关复合索引和前缀的行为的更多信息,请参见复合索引和前缀

复合多键索引还可以支持排序操作,例如以下示例:

db.inventory.find( ).sort( { "stock.size": 1, "stock.quantity": 1 } )
db.inventory.find( { "stock.size": "M" } ).sort( { "stock.quantity": 1 } )

有关复合索引和排序操作的行为的更多信息,请参见使用索引对查询结果进行排序