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}})
相关推荐
夜泉_ly2 小时前
MySQL -安装与初识
数据库·mysql
qq_529835353 小时前
对计算机中缓存的理解和使用Redis作为缓存
数据库·redis·缓存
月光水岸New5 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6755 小时前
数据库基础1
数据库
我爱松子鱼5 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo5 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser6 小时前
【SQL】多表查询案例
数据库·sql
Galeoto6 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
人间打气筒(Ada)7 小时前
MySQL主从架构
服务器·数据库·mysql
leegong231117 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql