二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • 最佳实践

  • 迎刃而解

  • Nginx

  • Php

  • Zabbix

  • AWS

  • Prometheus

  • Grafana

  • Loki

  • CentOS

  • Supervisord

  • Systemd

  • Docker

  • Docker-Compose

  • Rancher

  • Ansible

  • OpenLdap

  • GitLab

  • GitHub

  • Etcd

  • Consul

  • RabbitMQ

  • Kafka

  • Mysql

  • MongoDB

    • 认识了解MongoDB
    • CentOS-7部署MongoDB
    • MongoDB增删改查基本操作
    • MongoDB日常运维之用户管理
    • MongoDB索引方面的学习实践
      • 准备数据
      • 创建索引
      • 数据查询
      • 其他进阶
        • 数组索引
        • 全文索引
        • 其他补充
    • MongoDB关联查询的学习以及实践
  • OpenVPN

  • Kvm

  • VMware

  • 配置文件详解

  • Other

  • 运维观止
  • MongoDB
二丫讲梵
2022-02-27
目录

MongoDB索引方面的学习实践

文章发布较早,内容可能过时,阅读注意甄别。

cmdb 使用 MongoDB 作为底层数据存储,为了便于检索,本文将探讨研究一些 MongoDB 的索引使用。

# 准备数据

在开始学习了解之前,先准备一些测试数据如下:

db.datas.insert(
    [
        {"datas_identify":"eryajf","data":[{"name":"aaa","identify":"aaa-1","create_time":"2020-01-01"}]},
        {"datas_identify":"eryajf","data":[{"name":"bbb","identify":"bbb-1","create_time":"2021-01-01"}]},
        {"datas_identify":"eryajf","data":[{"name":"ccc","identify":"ccc-1","create_time":"2022-01-01"}]},
        {"datas_identify":"eryajf","data":[{"name":"ddd","identify":"ddd-1","create_time":"2023-01-01"}]},
        {"datas_identify":"eryajf","data":[{"name":"eee","identify":"eee-1","create_time":"2024-01-01"}]},
        {"datas_identify":"liql","data":[{"name":"fff","identify":"fff-1","create_time":"2024-01-01"}]},
        {"datas_identify":"liql","data":[{"name":"ggg","identify":"ggg-1","create_time":"2026-01-01"}]},
        {"datas_identify":"liql","data":[{"name":"hhh","identify":"hhh-1","create_time":"2027-01-01"}]},
        {"datas_identify":"liql","data":[{"name":"iii","identify":"iii-1","create_time":"2028-01-01"}]},
        {"datas_identify":"liql","data":[{"name":"aaa","identify":"aaa-1","create_time":"2029-01-01"}]}])
1
2
3
4
5
6
7
8
9
10
11
12

常规情况下,我们可以针对具体字段进行查询:

db.getCollection('datas').find({"datas_identify":"eryajf"})
db.getCollection('datas').find({"data.name":"aaa"})
1
2

这种针对指定字段的查询没有问题,不过如果想要实现一个智能识别的,或者针对当前数据表能够全表搜索的,就需要用到索引了。

# 创建索引

MongoDB 可以对任意字段建立全文索引(text index),但需要注意:1 个 collection 中只能包含至多 1 个全文索引,且只能对 String 或 String 数组的字段建立文本索引。

我们可以通过如下命令创建一个文本索引:

db.datas.createIndex({datas_identify: "text"})
1

这个语句表示将datas_identify字段添加为全文索引,当然也可以指定多个字段,方法如下:

db.datas.createIndex({datas_identify: "text", name: "text"})
1

执行完毕之后,可以通过如下命令查看当前集合的索引:

$ db.datas.getIndexes()

/* 1 */
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_"
    },
    {
        "v" : 2,
        "key" : {
            "_fts" : "text",
            "_ftsx" : 1
        },
        "name" : "datas_identify_text",
        "weights" : {
            "datas_identify" : 1
        },
        "default_language" : "english",
        "language_override" : "language",
        "textIndexVersion" : 3
    }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • 索引创建之后默认支持的语言是英文,需要注意,MongoDB 目前还不支持中文,点击这里 (opens new window)可以查看当前支持的语言列表。
  • 当索引字段有多个的时候,可以通过 weights 字段控制索引字段的权重。

# 数据查询

查询的语句格式如下:

{
 $text:
 	{
		$search: <string>,
		$language: <string>,
		$caseSensitive: <boolean>,
		$diacriticSensitive: <boolean>
 	}
}
1
2
3
4
5
6
7
8
9
  • $search:后面跟的是将要搜索的关键字。
  • $language:指定搜索的语言。
  • $caseSensitive:设置是否区分大小写。
  • $diacriticSensitive设置是否区别发音符号。

那么查询 datas_identify为eryajf的方式如下:

$ db.datas.find({ $text: {$search: "eryajf"}})
1

# 其他进阶

# 数组索引

MongoDB 可以给一个数组添加索引,从而提高指定数组的检索效率。

创建一个数组的索引:

$ db.datas.createIndex({"data.name":"text","data.identify":"text","datas_identify":"text"})
1

然后直接进行检索:

$ db.datas.find({ $text: {$search: "bbb"}})
/* 1 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebd6"),
    "datas_identify" : "eryajf",
    "data" : [
        {
            "name" : "bbb",
            "identify" : "bbb-1",
            "create_time" : "2021-01-01"
        }
    ]
}


$ db.datas.find({ $text: {$search: "aaa"}})
/* 1 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebde"),
    "datas_identify" : "liql",
    "data" : [
        {
            "name" : "aaa",
            "identify" : "aaa-1",
            "create_time" : "2029-01-01"
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebd5"),
    "datas_identify" : "eryajf",
    "data" : [
        {
            "name" : "aaa",
            "identify" : "aaa-1",
            "create_time" : "2020-01-01"
        }
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

这是在明确知道数组内字段的情况下的方案,在一些实际应用场景中,一个数组内的字段有可能是不固定的,这种时候就没办法对指定字段进行索引了。这个时候就需要用到全文索引了。

# 全文索引

建立一个通配符全文索引的方法是:

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

全文索引创建完毕之后,我们可以对整个集合进行检索。

测试效果如下:

$ db.datas.find({ $text: { $search: "aaa" } })
/* 1 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebde"),
    "datas_identify" : "liql",
    "data" : [
        {
            "name" : "aaa",
            "identify" : "aaa-1",
            "create_time" : "2029-01-01"
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebd5"),
    "datas_identify" : "eryajf",
    "data" : [
        {
            "name" : "aaa",
            "identify" : "aaa-1",
            "create_time" : "2020-01-01"
        }
    ]
}

# ============ #

$ db.datas.find({ $text: { $search: "2022" } })
/* 1 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebd7"),
    "datas_identify" : "eryajf",
    "data" : [
        {
            "name" : "ccc",
            "identify" : "ccc-1",
            "create_time" : "2022-01-01"
        }
    ]
}

# ============ #

$ db.datas.find({ $text: { $search: "2024" } })
/* 1 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebda"),
    "datas_identify" : "liql",
    "data" : [
        {
            "name" : "fff",
            "identify" : "fff-1",
            "create_time" : "2024-01-01"
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("621b7bbff00df89221ebebd9"),
    "datas_identify" : "eryajf",
    "data" : [
        {
            "name" : "eee",
            "identify" : "eee-1",
            "create_time" : "2024-01-01"
        }
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

# 其他补充

基于全文索引的搜索,有一些需要注意的点,这里做一下记录。

  • 如果查询中有通配符,使用如下方式转义

    $ db.datas.find({ $text: { $search: "\"10.6.6.66\"" } })
    
    1
  • 多条件逻辑或

    $ db.datas.find({ $text: { $search: "2024 bbb" } })
    
    1
  • 多条件逻辑与

    $ db.datas.find({ $text: { $search: '"2024" "liql"' } })
    
    1
  • 如果想要排除某个结果,则用-查询

    $ db.datas.find({ $text: { $search: '"2024" -liql' } })
    /* 1 */
    {
      	"_id" : ObjectId("621b7bbff00df89221ebebd9"),
        "datas_identify" : "eryajf",
        "data" : [
            {
      	        "name" : "eee",
          	    "identify" : "eee-1",
              	"create_time" : "2024-01-01"
            }
        ]
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • golang 检索时的代码

    type Data struct {
    	DatasIdentify string `json:"datas_identify"`
    	Data          []struct {
    		Name       string `json:"name"`
    		Identify   string `json:"identify"`
    		CreateTime string `json:"create_time"`
    	} `json:"data"`
    }
    
    func FindTest() {
    	filters := bson.D{}
    	filter := bson.E{Key: "datas_identify", Value: "eryajf"}
    	searchFilter := bson.E{Key: "$text", Value: bson.M{"$search": "2022"}}
    	filters = append(filters, filter, searchFilter)
    	datas, err := ListData(filters, options.FindOptions{})
    	if err != nil {
    		fmt.Printf("get data failed: %v\n", err)
    	}
    	for _, v := range datas {
    		fmt.Println(v)
    	}
    
    }
    
    // ListData 获取数据列表
    func ListData(filter bson.D, options options.FindOptions) ([]*Data, error) {
    	table := DB.Collection("datas")
    	cus, err := table.Find(ctx, filter, &options)
    	if err != nil {
    		fmt.Printf("find data failed: %v\n", err)
    	}
    	defer func(cus *mongo.Cursor, ctx context.Context) {
    		err := cus.Close(ctx)
    		if err != nil {
    			return
    		}
    	}(cus, ctx)
    
    	list := make([]*Data, 0)
    	for cus.Next(ctx) {
    		data := new(Data)
    		err := cus.Decode(&data)
    		if err != nil {
    			fmt.Printf("decode data failed: %v\n", err)
    		}
    		list = append(list, data)
    	}
    
    	return list, nil
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50

以上就是 MongoDB 中索引的一些实践,一些内容需要结合实际场景进行使用。

  • 参考:
    • MongoDB 全文搜索 (opens new window)
    • Mongodb 全文搜索实战 (opens new window)
    • MongoDB 之索引 (opens new window)
    • MongoDB 中的全文本搜索 (opens new window)
    • 通配符索引 (opens new window)
    • How to AND and NOT in MongoDB $text search (opens new window)
微信 支付宝
#MongoDB
上次更新: 2024/07/04, 22:40:37
MongoDB日常运维之用户管理
MongoDB关联查询的学习以及实践

← MongoDB日常运维之用户管理 MongoDB关联查询的学习以及实践→

最近更新
01
记录二五年五一之短暂回归家庭
05-09
02
学习周刊-总第210期-2025年第19周
05-09
03
学习周刊-总第209期-2025年第18周
05-03
更多文章>
Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式