针对嵌入对象和数组的通配符索引
通配符索引在对嵌入式对象和数组字段进行索引时具有特定行为:
如果字段是对象,则通配符索引会下降到对象中并对其内容进行索引。通配符索引会继续下降到遇到的任何其他嵌入式文档。
如果字段是大量,则通配符索引将遍历大量并对每个元素进行索引:
如果元素是对象,则通配符索引下降到该对象以索引其内容。
如果元素是大量(即,直接嵌入到父大量中的大量),则通配符索引不会遍历嵌入式大量,而是将整个大量作为单个值进行索引。
对于所有其他字段,索引存储原始值。原始值是非对象、非数组值。
通配符索引会继续遍历任何其他嵌入式对象或数组,直到达到原始值。 然后,它会对原始值以及该字段的完整路径进行索引。
嵌入式对象上的通配符索引
当通配符索引遇到嵌入式对象时,它会深入到该对象并对其内容进行索引。 示例,考虑此文档:
db.users.insertOne( { account: { username: "SuperAdmin01", contact: { phone: "123-456-7890", email: "xyz@example.com" }, access: { group: "admin" } } } )
包含 account
字段的通配符索引下降到account
对象,以遍历其内容并为其编制索引:
对于每个本身就是对象的子字段(例如
account.contact
和account.access
),索引会下降到对象中并记录其内容。对于所有其他子字段,索引会将原始值记录到索引中。
根据示例文档,通配符索引会将以下记录添加到索引中:
"account.username" : "SuperAdmin01"
"account.contact.phone" : "123-456-7890"
"account.contact.email" : "xyz@example.com"
"account.access.group" : "admin"
数组上的通配符索引
当通配符索引遇到大量时,它会遍历该大量以对其元素进行索引。 如果大量元素本身就是一个大量(嵌入式大量),则索引会将整个嵌入式大量记录为一个值,而不是遍历其内容。
示例,考虑此文档:
db.fleet.insertOne( { "ship": { "coordinates" : [ [-5, 10], [-7, 8] ], "type": "Cargo Ship", "captains": [ { "name": "Francis Drake", "crew": [ "first mate", "carpenter" ] } ] } } )
包含ship
字段的通配符索引深入到对象中,以遍历其内容并对其内容进行索引:
对于大量中的每个元素:
如果元素本身是一个大量(如在嵌入式大量中),则索引会将整个大量记录为一个值。
如果元素是对象,则索引下降到该对象以遍历并索引其内容。
如果该元素是原始值,则索引会记录该值。
对于非数组、非对象字段,索引会将原始值记录到索引中。
根据示例文档,通配符索引会将以下记录添加到索引中:
"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"
具有显式数组索引的查询
在索引期间,通配符索引不会记录大量中任何给定元素的大量位置。 但是, MongoDB仍可能使用通配符索引来完成包含具有一个或多个显式大量索引的字段路径(Field Path)的查询。
示例,考虑此文档:
db.fleet.insertOne( { "ship": { "coordinates" : [ [-5, 10], [-7, 8] ], "type": "Cargo Ship", "captains": [ { "name": "Francis Drake", "crew": [ "first mate", "carpenter" ] } ] } } )
创建包含ship
字段的通配符索引:
db.fleet.createIndex( { "ship.$**": 1 } )
ship.coordinates
和ship.captains
的索引记录不包括每个元素的大量位置。 在将元素记录到索引中时,通配符索引会忽略大量元素的位置。 但是,通配符索引仍可支持包含显式大量索引的查询。
MongoDB可以使用通配符索引来完成此查询:
db.fleet.find( { "ship.captains.0.name": "Francis Drake" } )
查询返回示例文档:
[ { _id: ObjectId("6350537db1fac2ee2e957efc"), ship: { coordinates: [ [ -5, 10 ], [ -7, 8 ] ], type: 'Cargo Ship', captains: [ { name: 'Francis Drake', crew: [ 'first mate', 'carpenter' ] } ] } } ]
MongoDB 无法使用通配符索引来完成此查询:
db.fleet.find( { "ship.coordinates.0.1": 10 } )
ship.coordinates
字段包含嵌入式数组。 通配符索引不记录嵌入式数组的各个值。 相反,它们会记录整个嵌入式大量。 因此,通配符索引不支持对嵌入式大量值的匹配, MongoDB通过集合扫描来完成查询。
数组索引限制
仅当路径包含8个或更少的显式大量索引时, MongoDB才能使用通配符索引来填充查询中的给定字段路径(Field Path)。 如果字段路径(Field Path)包含超过8显式索引,为完成查询, MongoDB会执行以下任一操作:
选择另一个符合条件的索引。
执行集合扫描。
通配符索引本身在索引文档时对其遍历文档的深度没有限制。 该限制仅适用于显式指定精确大量索引的查询。