MongoDB通配符索引详解(附带实例)
MongoDB 数据库支持在一个字段或一组字段上创建索引,以提高查询性能。MongoDB 支持灵活模式,这表明文档字段名在一个集合中可能会有所不同。我们可以使用通配符索引来支持对任意或未知字段的查询。
例如,在 MongoDB 数据库中创建通配符索引,需要使用通配符说明符($**)作为索引键,具体代码如下:
MongoDB 数据库仅当需要索引的字段未知或可能更改时,才可以使用通配符索引。通配符索引的性能通常不及针对特定字段的目标索引。如果集合包含阻止目标索引建立的任意字段名称,则应考虑重新构建模式以获得一致的字段名称。
通配符索引的具体行为描述如下:
另外,仅当满足以下所有条件时,通配符索引才支持覆盖查询:
请参考 employees 集合中以下通配符索引:
想要对单个字段创建通配符索引,可使用 db.collection.createIndex() 方法并在索引键中包含通配符说明符($**):
然后,通过以下操作在 attributes 字段上创建一个通配符索引:
最后,通配符索引支持对 attributes 或其嵌入式字段进行单字段查询,请看下面的查询代码示例:
结果输出如下:
如要在通配符索引中包含或排除字段,可以在 wildcardProjection 选项中指定所选的字段:
另外,使用 wildcardProjection 选项时有些限制,具体内容如下:
在下面的应用示例中,创建了一个 products 集合,其中包含以下文档:
然后,可以使用 wildcardProjection 选项在通配符索引中包含特定字段。如果设计人员需要经常查询某些文档字段,可以在 wildcardProjection 选项中指定这些字段以支持这些查询,不给索引增加不必要的臃肿。
下面的代码会创建一个通配符索引,其中包含 attributes.size 字段和 attributes.color 字段的所有标量值(即字符串和数字):
创建的索引支持对 wildcardProjection 选项中包含的任何标量值进行查询。例如,索引支持以下查询:
上述索引仅支持对 wildcardProjection 选项中包含的字段进行查询。在该示例中,MongoDB 数据库对以下查询执行集合扫描,因为其包含 wildcardProjection 选项中不存在的字段。
如果存在很少查询的文档字段,则可以创建省略这些字段的通配符索引。下面的代码在 products 集合中的所有文档字段上创建通配符索引,但在索引中省略了 attributes.memory 字段。
如果字段是嵌入式文档或数组(如 attributes.size),则通配符索引将对该字段进行递归并对所有内嵌的标量字段值进行索引。例如,索引支持以下查询:
如果要在所有字段(不包括_id)上创建通配符索引,可以使用通配符说明符($**)作为索引键,具体代码如下:
在下面的应用示例中,创建了一个 artwork 集合,其中包含以下文档:
首先,以下操作会在 artwork 集合中的所有文档字段(不包括_id)上创建通配符索引。
例如,该索引支持以下几种查询:
1) 查询一:
2) 查询二:
3) 查询三:
例如,在 MongoDB 数据库中创建通配符索引,需要使用通配符说明符($**)作为索引键,具体代码如下:
db.collection.createIndex({ "$**": <sortOrder> })在 MongoDB 数据库中,可以使用以下几个命令创建通配符索引:
- createIndexes;
- db.collection.createIndex();
- db.collection.createIndexes()。
MongoDB 数据库仅当需要索引的字段未知或可能更改时,才可以使用通配符索引。通配符索引的性能通常不及针对特定字段的目标索引。如果集合包含阻止目标索引建立的任意字段名称,则应考虑重新构建模式以获得一致的字段名称。
通配符索引的具体行为描述如下:
- 设计人员可以在一个集合中创建多个通配符索引。
- 通配符索引可涵盖与集合中其他索引相同的字段。
- 默认情况下,通配符索引会省略 _id 字段。如果想要将 _id 字段包含在通配符索引中,则必须明确指定 { "_id" : 1 } 字段。
- 通配符索引是稀疏索引,仅包含具有索引字段的文档的条目,即使索引字段包含空值也是如此。
- 通配符索引不同于通配符文本索引,并且与通配符文本索引不兼容。
- 通配符索引不支持使用$text操作符的查询。
另外,仅当满足以下所有条件时,通配符索引才支持覆盖查询:
- 查询规划器选择通配符索引来满足查询条件;
- 查询关键词可精确指定通配符索引所涵盖的一个字段;
- 查询投影明确排除 _id,仅包含查询字段;
- 查询指定的字段绝对不能是数组。
请参考 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 指示索引是包含还是排除该字段,具体说明如下:
- 0:表示已排除该字段;
- 1:表示包含该字段。
另外,使用 wildcardProjection 选项时有些限制,具体内容如下:
- 想要使用 wildcardProjection 选项,索引键必须为 $**;
- 通配符索引不支持在 wildcardProjection 选项中混用包含和排除语句,除非显示包含 _id 字段时。
在下面的应用示例中,创建了一个 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 }