首页 > 编程笔记 > MongoDB 阅读:4

MongoDB通配符索引详解(附带实例)

MongoDB 数据库支持在一个字段或一组字段上创建索引,以提高查询性能。MongoDB 支持灵活模式,这表明文档字段名在一个集合中可能会有所不同。我们可以使用通配符索引来支持对任意或未知字段的查询。

例如,在 MongoDB 数据库中创建通配符索引,需要使用通配符说明符($**)作为索引键,具体代码如下:
db.collection.createIndex({ "$**": <sortOrder> })
在 MongoDB 数据库中,可以使用以下几个命令创建通配符索引:
MongoDB 数据库仅当需要索引的字段未知或可能更改时,才可以使用通配符索引。通配符索引的性能通常不及针对特定字段的目标索引。如果集合包含阻止目标索引建立的任意字段名称,则应考虑重新构建模式以获得一致的字段名称。

通配符索引的具体行为描述如下:
另外,仅当满足以下所有条件时,通配符索引才支持覆盖查询:
请参考 employees 集合中以下通配符索引:
db.employees.createIndex({ "$**" : 1 })
以下操作查询单个字段lastName并从结果文档中投影出所有其他字段:
db.employees.find(
     { "lastName" : "king" },
     { "_id" : 0, "lastName" : 1 }
)
在上面的代码中,如果指定的 lastName 不是数组,则 MongoDB 数据库可以使用 $** 通配符索引来支持覆盖的查询。

对单个字段创建通配符索引

在 MongoDB 数据库中,单个字段上的通配符索引支持对索引字段的任何子字段进行查询,使用通配符索引来支持对事先不知道或因文档而异的字段名称的查询。

想要对单个字段创建通配符索引,可使用 db.collection.createIndex() 方法并在索引键中包含通配符说明符($**):
db.collection.createIndex( { "<field>.$**": <sortOrder> } )
首先,创建一个 products 集合,其中包含一个名称为 collectionsurvey3 的集合文档,具体代码如下:
db.products.insertMany([
  {
    product_name: "Spy Coat",
    attributes: {
      material: ["Tweed", "Wool", "Leather"],
      size: {
        length: 72,
        units: "inches"
      }
    }
  },
  {
    product_name: "Spy Pen",
    attributes: {
      colors: ["Blue", "Black"],
      secret_feature: {
        name: "laser",
        power: "1000",
        units: "watts"
      }
    }
  }
])

然后,通过以下操作在 attributes 字段上创建一个通配符索引:
db.products.createIndex({ "attributes.$**" : 1 })

最后,通配符索引支持对 attributes 或其嵌入式字段进行单字段查询,请看下面的查询代码示例:
db.products.find({ "attributes.size.length" : { $gt : 60 } })

结果输出如下:
[{
  _id: ObjectId("6347..."),
  product_name: "Spy Coat",
  attributes: {
    material: ["Tweed", "Wool", "Leather"],
    size: {
      length: 72,
      units: "inches"
    }
  }
}]

在通配符索引中包含或排除字段

在 MongoDB 数据库中创建通配符索引时,设计人员可以指定想要在索引中包含或排除的字段,具体内容如下:
如要在通配符索引中包含或排除字段,可以在 wildcardProjection 选项中指定所选的字段:
db.<collection>.createIndex(
  { "$**": <sortOrder> },
  {
    wildcardProjection: {
      "<field1>": <0 | 1>,
      "<field2>": <0 | 1>,
      ...
    }
  }
)
在上面的代码中,wildcardProjection 选项的值 0 或 1 指示索引是包含还是排除该字段,具体说明如下:
另外,使用 wildcardProjection 选项时有些限制,具体内容如下:
在下面的应用示例中,创建了一个 products 集合,其中包含以下文档:
db.products.insertMany([
  {
    item: "t-shirt",
    price: "39.99",
    attributes: {
      material: "cotton",
      color: "blue",
      size: {
        units: "cm",
        length: 76
      }
    }
  },
  {
    item: "milk",
    price: "6.99",
    attributes: {
      sellBy: "02-06-2024",
      type: "oat"
    }
  },
  {
    item: "laptop",
    price: "339.99",
    attributes: {
      memory: "8GB",
      size: {
        units: "inches",
        height: 10,
        width: 15
      }
    }
  }
])
在上面的代码中,每个文档都有一个包含产品详细信息的 attributes 字段,attributes 的子字段因产品而异。

然后,可以使用 wildcardProjection 选项在通配符索引中包含特定字段。如果设计人员需要经常查询某些文档字段,可以在 wildcardProjection 选项中指定这些字段以支持这些查询,不给索引增加不必要的臃肿。

下面的代码会创建一个通配符索引,其中包含 attributes.size 字段和 attributes.color 字段的所有标量值(即字符串和数字):
db.products.createIndex(
  { "$**": 1 },
  {
    wildcardProjection: {
      "attributes.size": 1,
      "attributes.color": 1
    }
  }
)
虽然索引键模式 $** 涵盖文档中的所有字段,但 wildcardProjection 选项将索引限制为仅包含所包含的字段。如果字段是嵌入式文档或数组(如 attributes.size),则通配符索引将对该字段进行递归并对所有内嵌的标量字段值进行索引。

创建的索引支持对 wildcardProjection 选项中包含的任何标量值进行查询。例如,索引支持以下查询:
db.products.find({ "attributes.size.height": 10 })
db.products.find({ "attributes.color": "blue" })

上述索引仅支持对 wildcardProjection 选项中包含的字段进行查询。在该示例中,MongoDB 数据库对以下查询执行集合扫描,因为其包含 wildcardProjection 选项中不存在的字段。
db.products.find ( { "item": "milk" } )

如果存在很少查询的文档字段,则可以创建省略这些字段的通配符索引。下面的代码在 products 集合中的所有文档字段上创建通配符索引,但在索引中省略了 attributes.memory 字段。
db.products.createIndex(
  { "$**": 1 },
  {
    wildcardProjection: {
      "attributes.memory": 0
    }
  }
)
虽然索引键模式 $** 涵盖文档中的所有字段,但 wildcardProjection 选项从索引中排除了 attributes.memory 字段的值。

如果字段是嵌入式文档或数组(如 attributes.size),则通配符索引将对该字段进行递归并对所有内嵌的标量字段值进行索引。例如,索引支持以下查询:
db.products.find( { "attributes.color" : "blue" } )
db.products.find( { "attributes.size.height" : 10 } )
上述索引不支持对 attributes.memory 字段进行查询,因为索引中省略了该字段。

对所有字段创建通配符索引

在 MongoDB 数据库中,可以通过创建通配符索引来支持对所有可能的文档字段进行查询,通配符索引支持对任意或未知字段名称进行查询。

如果要在所有字段(不包括_id)上创建通配符索引,可以使用通配符说明符($**)作为索引键,具体代码如下:
db.<collection>.createIndex({ "$**": <sortOrder> })
一般只有当需要索引的字段未知或可能更改时,才需要使用通配符索引。通配符索引的性能不及针对特定字段的目标索引。如果集合包含阻止目标索引建立的任意字段名称,则应考虑重新构建模式以获得一致的字段名称。

在下面的应用示例中,创建了一个 artwork 集合,其中包含以下文档:
db.artwork.insertMany([
  {
    name: "Scream",
    artist: "king",
    style: "modern",
    themes: ["humanity", "horror"]
  },
  {
    name: "Acrobats",
    artist: {
      name: "tina",
      nationality: "French",
      yearBorn: 1877
    },
    originalTitle: "Les acrobates",
    dimensions: [65, 49]
  },
  {
    name: "Thinker",
    type: "sculpture",
    materials: ["bronze"],
    year: 1904
  }
])
在上面的代码中,每个文档都包含有关艺术品的详细信息。字段名称因文档而异,具体取决于作品的可用信息。

首先,以下操作会在 artwork 集合中的所有文档字段(不包括_id)上创建通配符索引。
db.artwork.createIndex({ "$**" : 1 })
以上索引支持对集合中任意字段进行单字段查询。如果文档包含嵌入式文档或数组,则通配符索引会遍历文档或数组,并将所有字段的值存储在文档或数组中。

例如,该索引支持以下几种查询:
1) 查询一:
db.artwork.find({ "style": "modern" })
结果输出如下:
{
  _id: ObjectId("6352...."),
  name: "Scream",
  artist: "king",
  style: "modern",
  themes: ["humanity", "horror"]
}

2) 查询二:
db.artwork.find({ "artist.nationality": "French" })
结果输出如下:
{
  _id: ObjectId("6352...."),
  name: "Acrobats",
  artist: {
    name: "tina",
    nationality: "French",
    yearBorn: 1877
  },
  originalTitle: "Les acrobates",
  dimensions: [65, 49]
}

3) 查询三:
db.artwork.find({ "materials": "bronze" })
结果输出如下:
{
  _id: ObjectId("6352...."),
  name: "Thinker",
  type: "sculpture",
  materials: ["bronze"],
  year: 1904
}

相关文章