为了索引保存数组值的字段,MongoDB为数组中的每个元素创建一个索引键。这些多键索引支持对数组字段的有效查询。可以在既包含标量值[1](例如字符串,数字)又包含嵌套文档的数组上构造多键索引。
[1] | 标量值是指既不是嵌入式文档也不是数组的值。 |
要创建多键索引,请使用以下
db.collection.createIndex()
方法:
如果任何索引字段是数组,MongoDB都会自动创建一个多键索引;您无需显式指定多键类型。
在版本3.4中更改:仅对于WiredTiger和内存中存储引擎,
从MongoDB 3.4开始,对于使用MongoDB 3.4或更高版本创建的多键索引,MongoDB跟踪哪个或哪些索引字段导致索引成为多键索引。跟踪此信息使MongoDB查询引擎可以使用更严格的索引范围。
对于唯一索引,唯一约束适用于集合中的各个文档,而不是单个文档。
因为唯一约束适用于单独的文档,所以对于 唯一的多键索引,文档可能具有导致重复索引键值的数组元素,只要该文档的索引键值不重复另一个文档的索引键值即可。
有关更多信息,请参见跨单独文档的唯一约束。
对于化合物多键索引,每个索引的文档可以具有至多一个索引字段,其值是一个数组。那是:
如果文档的一个以上要索引的字段是一个数组,则无法创建复合多键索引。例如,考虑一个包含以下文档的集合:
您不能在集合上创建复合多键索引,因为和字段都是数组。{ a: 1, b: 1 }
a
b
或者,如果已经存在复合多键索引,则不能插入违反此限制的文档。
考虑一个包含以下文档的集合:
复合多键索引是允许的,因为对于每个文档,仅由复合多键索引索引的一个字段是一个数组;即,没有文档包含
和字段的数组值。{ a: 1, b: 1 }
a
b
但是,在创建复合多键索引之后,如果您尝试插入a
和b
字段均为数组的文档,则MongoDB将使插入失败。
如果字段是文档数组,则可以为嵌入的字段建立索引以创建复合索引。例如,考虑一个包含以下文档的集合:
您可以在上创建复合索引。在限制至多一个索引字段可以是一个数组也适用。{ "a.x": 1, "a.z": 1 }
有关示例,请参见带有嵌入式文档的索引数组。
也可以看看
由于MongoDB 3.6中对数组字段的排序行为发生了变化,因此在对使用多键索引建立索引的数组上进行排序时 ,查询计划包括一个阻塞的SORT阶段。新的排序行为可能会对性能产生负面影响。
在阻塞式SORT中,必须在排序步骤中使用所有输入,然后才能产生输出。在非阻塞或索引排序中,排序步骤扫描索引以按请求的顺序产生结果。
您不能将多键索引指定为分片键索引。
但是,如果分片键索引是复合索引的前缀,并且如果其他键之一(即不属于分片键的键)对数组进行索引,则允许复合索引成为复合多键索引。复合多键索引可能会影响性能。
多键索引不能覆盖对数组字段的查询。
但是,从3.6开始,如果索引跟踪哪个字段或哪些字段导致索引成为多键,则多键索引可以覆盖非数组字段的查询。在MongoDB 3.4或更高版本中在MMAPv1 [#] _以外的存储引擎上创建的多键索引会跟踪此数据。
[2] | 从4.2版开始,MongoDB删除不推荐使用的MMAPv1存储引擎。 |
当查询过滤器为整个数组指定一个完全匹配项时,MongoDB可以使用多键索引查找查询数组的第一个元素,但是不能使用多键索引扫描来查找整个数组。相反,在使用多键索引查找查询数组的第一个元素之后,MongoDB检索关联的文档并过滤其数组与查询中的数组匹配的文档。
例如,考虑一个inventory
包含以下文档的集合:
该集合在ratings
字段上具有多键索引:
以下查询查找ratings
字段为数组的文档:[ 5, 9 ]
MongoDB可以使用多键索引来查找数组5
中任何位置的文档ratings
。然后,MongoDB检索这些文档并筛选其ratings
数组等于查询array的文档。[ 5, 9 ]
考虑survey
包含以下文档的集合:
在字段上创建索引ratings
:
由于该ratings
字段包含一个数组,因此索引ratings
为multikey。多键索引包含以下三个索引键,每个都指向同一文档:
2
,5
和9
。您可以在包含嵌套对象的数组字段上创建多键索引。
考虑具有inventory
以下形式的文档的集合:
以下操作在stock.size
和stock.quantity
字段上创建一个多键索引:
复合多键索引可以支持带有既包含索引字段又包含仅包含索引前缀的谓词的查询"stock.size"
,如以下示例所示:
有关MongoDB如何组合多键索引范围的详细信息,请参阅 Multikey Index Bounds。有关复合索引和前缀的行为的更多信息,请参见复合索引和前缀。
复合多键索引还可以支持排序操作,例如以下示例:
有关复合索引和排序操作的行为的更多信息,请参见使用索引对查询结果进行排序。