“文档” 菜单
文档首页
/
MongoDB Manual
/ / / /

针对嵌入对象和数组的通配符索引

在此页面上

  • 嵌入式对象上的通配符索引
  • 数组上的通配符索引
  • 了解详情

通配符索引在对嵌入式对象和数组字段进行索引时具有特定行为:

  • 如果字段是对象,则通配符索引会下降到对象中并对其内容进行索引。通配符索引会继续下降到遇到的任何其他嵌入式文档。

  • 如果字段是数组,则通配符索引将遍历数组并对每个元素进行索引:

    • 如果元素是对象,则通配符索引会下降到对象以索引其内容。

    • 如果元素是数组(即直接嵌入到父数组中的数组),则通配符索引不会遍历嵌入式数组,而是将整个数组作为单个值进行索引。

  • 对于所有其他字段,索引存储原始值。原始值是非对象、非数组值。

通配符索引会继续遍历任何其他嵌入式对象或数组,直到达到原始值。然后,它会对原始值以及该字段的完整路径进行索引。

当通配符索引遇到嵌入式对象时,它会深入到该对象并对其内容进行索引。例如,考虑此文档:

db.users.insertOne( {
account: {
username: "SuperAdmin01",
contact: {
phone: "123-456-7890",
email: "xyz@example.com"
},
access: {
group: "admin"
}
}
} )

包含 account字段的通配符索引下降到account对象,以遍历其内容并为其编制索引:

  • 对于每个本身就是对象的子字段(例如 account.contactaccount.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 仍可能使用通配符索引来完成包含具有一个或多个显式数组索引的字段路径的查询。

例如,考虑此文档:

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.coordinatesship.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 才能使用通配符索引来填充查询中的给定字段路径。如果字段路径包含超过8显式索引,为完成查询,MongoDB 会执行以下任一操作:

  • 选择另一个符合条件的索引。

  • 执行集合扫描。

通配符索引本身在索引文档时对其遍历文档的深度没有限制。该限制仅适用于显式指定精确数组索引的查询。

  • BSON 深度限制

  • 点符号

  • 通配符索引限制

← 通配符索引参考