Mongodb的通配符索引

学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第95篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。威赞文章都是结合官方文档,翻译整理而来,并对每个知识点的描述都认真思考和实践,对难以理解的地方,使用简单容易理解的方式进行阐述。

Mongodb支持灵活的数据结构定义,同一个Collection的不同文档,可以拥有不同的字段,使用相同字段存储不同的数据类型,甚至缺少某些字段。这样灵活的数据结构,在构建索引时,应用开发人员或数据库管理员无法知道当前文档是否包含该字段,或者字段的名称是什么。Mongodb提供了通配符索引,来满足这样的应用场景。使用通配符索引,为未知字段或不确定的字段来添加索引。

概述

创建Mongodb索引时,使用通配符$**来创建通配符索引

db.collection.createIndex({ "$**": <sortOrder>})

为嵌入式文档添加索引

db.collection.createIndex({"<field>.$**": <sortOrder>})

只有当用户在不确定字段未来是否会变化,或不清楚需要创建索引的字段时,才使用通配符来创建索引。通配符索引和普通的确定字段索引的行为不一样。如果集合中因为随意的字段名称导致不能够创建索引,Mongodb官方建议首先统一字段名称。而不是创建通配符索引来代替普通索引。通配符索引,适用于下面几个场景

  • 系统应用查询的集合中文档字段不同,为该集合添加通配符索引,包含所有需要查询的字段
  • 针对字段不一致的嵌入式文档的查询,为该嵌入式文档创建通配符索引
  • 使用复合通配符索引,能够提高常用查询条件的索引覆盖率。

使用和限制

  • 用户可以在同一个集合当中添加多个通配符索引
  • 通配符索引字段可以包含其他索引字段
  • 默认通配符字段不包含_id字段。用户需要在wildcardProjection字段中显示指定_id字段
  • 通配符字段索引时稀疏的,只包含带有包含通配符字段的文档。即使该字段是null值,也会被包含在索引中
  • 通配符索引和通配符文本索引,不是同一个索引。通配符索引不支持使用$text进行文本查询。
  • 当符合下面所有条件时,通配符索引才能够支持索引覆盖查询
    • Mongodb选择通配符索引作为选中的索引
    • 查询过滤条件中只包含通配符索引当中的字段
    • 查询结果显示指定不包含_id字段,只包含查询字段
    • 指定的查询字段,不是数组字段

如在employees集合中添加通配符索引

db.employees.createIndex({"$**": 1})

该索引能够覆盖查询

db.employees.find({"last_name": "Doe"}, {"last_name": 1, "_id": 0})

查看该查询的执行计划

应用

创建集合products并插入数据

db.products.insertMany([
    {
        product_name: "Spy Coat",
        attributes: {
            material: [ "Tweed", "Wool", "Leather" ],
            size: {
                length: 72,
                unites: "inches"
            }
        }
    }, {
        product_name: "Spy Pen",
        attributes: {
            colors: [ "Blue", "Black" ],
            secret_feature: {
                name: "laser",
                power: "1000",
                units: "watts"
            }
        }
    }
])

为字段添加通配符索引

该通配符索引支持字段attributes和attributes文档中的字段查询

db.products.createIndex({"attributes.$**": 1})

查询文档数据

db.products.find({"attributes.size.length": {$gt: 60}})
db.products.find({"attributes.material": "Leather"})
db.products.find({"attributes.secret_feature.name": "laser"}, {"attributes.secret_colors": 1, product_name: 1,  "_id": 0})

指定通配符索引包含的字段

Mongodb允许用户创建通配符索引时,指定包含哪些字段或不包含哪些字段。如文档中包含多个嵌入式文档,用户可以包含这些嵌入式文档和嵌入式文档中的字段。或者用户添加通配符索引时,排除不需要查询的字段。

按照下面的语法指定包含的字段,其中1表示包含,0表示不包含

vb 复制代码
`db.collection.createIndex(
  {
    "$**": <sortOrder>
  },
  {
    "wildcardProjection": {
      <field1>: <0|1>,
      <field2>: <0|1>,
      ...
      <fieldn>: <0|1>,
    }
  }
)`

指定包含哪些字段时,有下面两个限制

  • wildcardProjection只能用于通配符索引中

  • 除了_id字段外,通配符索引创建时,不能同时指定包含和排除哪些字段。如下面这样的写法,是不可用的

    {
    "wildcardProjection": {
    "attributes": 0,
    "users": 1
    }
    }

而带有_id字段时,指定包含_id字段而不包含其他字段,是可以的

{
  "wildcardProjection": {
    "attributes": 0,
    "_id": 1
  }
}

在products集合添加索引,包含attributes文档中的size和color字段

db.products.createIndex({
    "$**": 1
}, {
    wildcardProjection: {
        "attributes.colors": 1,
        "attributes.size": 1
    }  
}) 

在products集合添加索引,不包含attributes文档中的memory字段

db.products.createIndex({
    "$**": 1
}, {
    wildcardProjection: {
        "attributes.memory": 0
    }  
}) 

在集合的所有字段上添加索引

添加集合artwork并插入数据

db.artWork.insertMany([
    {
        title: "The Scream",
        artist: "Edvard Munch",
        year: 1893,
        medium: "oil on canvas",
        dimensions: {
            height: 91,
            width: 73
        }
    }, {
        title: "The Persistence of Memory",
        artist: "Salvador Dali",
        year: 1931,
        medium: "oil on canvas",
        dimensions: {
            height: 24,
            width: 33
        }
    }
])

为所有字段添加索引

db.artWork.createIndex({"$**": 1})

查询数据

db.artWork.find({"year": 1931})
db.artWork.find({"dimensions.height": {$gt: 30}})
相关推荐
小蜗牛慢慢爬行16 分钟前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
hanbarger19 分钟前
nosql,Redis,minio,elasticsearch
数据库·redis·nosql
微服务 spring cloud41 分钟前
配置PostgreSQL用于集成测试的步骤
数据库·postgresql·集成测试
先睡43 分钟前
MySQL的架构设计和设计模式
数据库·mysql·设计模式
弗罗里达老大爷1 小时前
Redis
数据库·redis·缓存
仰望大佬0071 小时前
Avalonia实例实战五:Carousel自动轮播图
数据库·microsoft·c#
学不透java不改名1 小时前
sqlalchemy连接dm8 get_columns BIGINT VARCHAR字段不显示
数据库
一只路过的猫咪2 小时前
thinkphp6使用MongoDB多个数据,聚合查询的坑
数据库·mongodb
呼啦啦啦啦啦啦啦啦3 小时前
【MySQL篇】事务的认识以及四大特性
数据库·mysql