MongoDB 简介与操作

前言

MongoDB版本:5.0.5

什么是MongoDB

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。与此同时,其与生俱来的高可用、高水平扩展能力使得它在处理海量、高并发的数据应用时颇具优势。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

MongoDB主要特征

  1. MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。

  1. Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。

  1. 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName="Sameer",Address="8 Gandhi Road")来实现更快的排序。

  1. 你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。

  1. 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。

  1. MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。

  1. Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。

  1. Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。

  1. Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。

  1. GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。

  1. MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。

  1. MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。

MongoDB数据结构

MongoDB 数据结构和我们常用的关系性数据库(RDBMS)的概念模型类似,下面通过对比二者可以清晰了解。

SQL术语概念

MongoDB术语概念

数据库(database)

数据库(database)

表(table)

集合(collection)

行(row)

文档(document)

列(column)

字段(field)

索引(index)

索引(index)

主键(primary key)

对象ID(object id)

表链接(table joins)

聚合操作($lookup)

视图(view)

视图(view)

通过下面实例,我们可以更加直观理解MongoDB 中的一些概念。

文档(document):一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。

集合(collection):MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

数据库(database):MongoDB 使用集合对文档进行分组,使用数据库对集合进行分组。一个MongoDB 实例可以承载多个数据库,每个数据库有零个或多个集合。一个值得推荐的做法是将单个应用程序的所有数据都存储在同一个数据库中。在同一个MongoDB 服务器上存储多个应用程序或用户的数据时,使用单独的数据库会非常有用。

基本操作

连接

这里使用MongoDB shell 来连接 MongoDB 服务器。你也可以使用其他高级语言(如:PHP、Go 等)或则数据库工具(如:Navicat)来连接 MongoDB。

  • 标准 URI 连接

语法如下

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

参数解析:

mongodb:这是固定的格式,必须要指定。

username:password@:可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登录这个数据库

host1:必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。

port:可选的指定端口,如果不填,默认为27017

/database:如果指定username:password@,连接并验证登录指定数据库。若不指定,默认打开 test 数据库。

?options:是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&或;(分号)隔开

实例如下:

mongodb://[email protected]:27017/?authSource=admin

  • shell 连接

mongo --host 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase=admin

数据库

MongoDB 使用集合对文档进行分组,使用数据库对集合进行分组。一个 MongoDB 中可以创建多个数据库,每个数据库有自己的集合和去权限。

数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串。

  • 不能是空字符串("")。

  • 不得含有' '(空格)、.、$、/、\和\0 (空字符)。

  • 应全部小写。

  • 最多64字节。

MongoDB 预留了几个特殊的数据库。

  • admin:admin 数据库主要保存 root 用户的角色,system.users 表存储用户。

  • local:local 数据库是不会复制到其他分片,可以用来存储限于本地单台服务器的任意集合。

  • config:当 Mongo 用于分片设置时,config 数据库在内部使用,用于保存分片相关信息。

创建数据库

MongoDB 创建数据库的语法格式如下:

use DATABASE_NAME

如果数据库不存在,则创建成功,否则切换到指定数据库。

创建一个 test 数据库

> use book
switched to db book

查看所有数据库,使用 show dbs(show databases):

> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

发现新创建数据库不存在, 要显示它,我们需要向 book 数据库插入数据。

> use book
switched to db book
> db.book.insert({ title: "MongoDB 从入门到放弃"})
WriteResult({ "nInserted" : 1 })
> show dbs
admin   0.000GB
book    0.000GB
config  0.000GB
local   0.000GB

MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中。

删除数据库

MongoDB 删除数据库的语法格式如下:

db.dropDatabase()

集合

集合就是一组文档。如果将文档比作关系数据库中的行,那么一个集合就相当于一张表。其中 MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素!

创建集合

语法格式:

db.createCollection(name, options)

参数说明:

  • name: 要创建的集合名称

  • options: 可选参数, 指定有关内存大小及索引的选项

其中 options 可以是如下参数:

字段

类型

描述

capped

布尔

(可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。当该值为 true 时,必须指定 size 参数

size

布尔

(可选)为固定集合指定一个最大值,即字节数。如果 capped 为 true,也需要指定该字段。

max

数值

(可选)指定固定集合中包含文档的最大数量。

实例如下:

在 shop 数据库中创建一个集合 book。

> db.createCollection("book")
{ "ok" : 1 }

在 shop 数据库中创建一个固定集合 book,整个集合空间大小 10000 B, 文档最大个数为 1000 个。

> db.createCollection("book",{capped:true,size:10000,max:1000})
{ "ok" : 1 }

查看集合

> show collections
book

删除集合

语法格式:

db.collection.drop()

实例如下:

在数据库 book 中,我们可以先通过 show collections 命令查看已存在的集合,再删除集合 book,再查看校验:

> show collections
book
> db.book.drop()
true
> show collections
>

文档

插入文档

MonfoDB Shell 将一个或多个文档插入集合使用 db.collection.insert()。

语法如下:

db.collection.insert(
   <document or array of documents>,
   {
     writeConcern: <document>,
     ordered: <boolean>
   }
)

参数说明:

  • document:一个火一组文档写入集合

  • writeConcern:可选。写入策略,默认为 1,即要求确认写操作,0 是不要求。

  • ordered:可选。默认 true。如果 true,对数组中的文档进行有序插入,如果其中一个文档发生错误,MongoDB 将返回而不处理数组中的其余文档。如果是false,则执行无序插入,如果其中一个文档发生错误,则继续处理数组中的剩余文档。

返回结果:

  • 单个插入的 WriteResult 对象。

  • 用于批量插入的 BulkWriteResult 对象。

实例如下:

我们向shop 数据库中 book 集合中插入一个文档:

> db.book.insert({
        "title" : "MongoDB 从入门到放弃",
        "description" : "MongoDB 是一个非关系型数据库",
        "type" : "literature",
        "author" : "mongo",
        "tags" : [ "mongodb", "database", "NoSQL"],
        "likes" : 100,
        "price" : 88.88,
        "publishedDate": new Date()
})
WriteResult({ "nInserted" : 1 })

我们向shop 数据库中 book 集合中插入多个文档:

> db.book.insert([
{
        "title" : "Mysql 从入门到放弃",
        "description" : "Mysql 是一个关系型数据库",
        "type" : "literature",
        "author" : "mysql",
        "tags" : [ "mysql", "database", "sql"],
        "likes" : 99,
        "price" : 77.77,
        "publishedDate": new Date()
},
 {
     title: "Oracle 从入门到放弃",
     description: 'Oracle 是一个关系型数据库',
     type: "literature",
     tags: ['oracle',  'database',  'sql'],
     likes: 66,
     price: 99.99,
     publishedDate: new Date()
 }
])
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 2,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})

MongoDB shell 提供了以下方法来将文档插入到集合中:

  • 要插入单个文档,请使用 db.collection.insertOne()。

  • 要插入多个文档,请使用 db.collection.insertMany()。

查询文档

MongoDB 查询文档使用 find() 方法。find() 方法以非结构化的方式来显示所有文档。

语法如下:

db.collection.find(query, projection, options)

参数说明:

  • query:可选。指定使用查询操作符的选择过滤器。要返回一个集合中的所有文档,请省略此参数或传递一个空文档({})。

  • projection:可选。指定要返回的符合查询过滤器的文档中的字段。如果要返回匹配文件中的所有字段,可以省略这个参数。

  • options:可选。指定查询的附加选项。这些选项修改查询行为和结果的返回方式。

如需易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:

db.collection.find().pretty()

实例如下:

  • 查询集合 book 中的所有文档数据

> db.book.find().pretty()
{
        "_id" : ObjectId("6421be39ca9c68bad525f89e"),
        "title" : "MongoDB 从入门到放弃",
        "description" : "MongoDB 是一个非关系型数据库",
        "type" : "literature",
        "author" : "mongo",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100,
        "price" : 88.88,
        "publishedDate" : ISODate("2023-03-23T16:03:05.493Z")
}
{
        "_id" : ObjectId("6421be39ca9c68bad525f89f"),
        "title" : "Mysql 从入门到放弃",
        "description" : "Mysql 是一个关系型数据库",
        "type" : "literature",
        "author" : "mysql",
        "tags" : [
                "mysql",
                "database",
                "sql"
        ],
        "likes" : 99,
        "price" : 77.77,
        "publishedDate" : ISODate("2023-03-23T16:03:05.493Z")
}
{
        "_id" : ObjectId("6421be39ca9c68bad525f8a0"),
        "title" : "Oracle 从入门到放弃",
        "description" : "Oracle 是一个关系型数据库",
        "type" : "literature",
        "tags" : [
                "oracle",
                "database",
                "sql"
        ],
        "likes" : 66,
        "price" : 99.99,
        "publishedDate" : ISODate("2023-03-23T16:03:05.493Z")
}
  • 查询 book集合中_id等于xxx的文档:

db.book.find({ "_id": ObjectId("6421be39ca9c68bad525f89e")})
  • 操作使用$in操作符来返回 book 集合中_id等于xxx1或 xxx2 的文档:

db.book.find(
   { _id: { $in: [ ObjectId("6421be39ca9c68bad525f89e"), ObjectId("6421be39ca9c68bad525f89f") ] } }
)
  • 操作使用$gt操作符,返回 book 集合中所有出生日期大于new Date()的文档:

 db.book.find( { publishedDate: { $gt: new Date('2023-03-23 16:00:00.000') } } )
  • 操作使用$regex操作符来返回 book 集合中 author字段以 likes 开头的文档(或为 "LIKE xxx%")。

db.book.find(
   { "author": { $regex: /^My/ } }
)
  • 结合比较运算符来指定一个字段的范围。操作从book 集合中返回 price 在 A 和 B 之间的文档(排他性):

db.book.find( { price: { $gt: 88, $lt: 100} } )
  • 操作 book 集合中返回所有 price 大于等于 88.88 且 author 不存在的文档:

> db.book.find( {
   price: { $gte: 77 },
   author: { $exists: false }
} )
  • 操作 book 集合中返回所有 price 大于 88.88 或 author 等于 Mongo 的文档:

> db.book.find( { $or:[  { price: { $gt: 88} }, { author: "Mongo"} ]  } )
  • 操作 book 集合中返回所有 publishDate 按倒序的文档:

> db.book.find().sort({ "publishDate": -1 })
  • 操作 book 集合中返回限制N个文档:

> db.book.find().limit(1)
  • 操作 book 集合中 返回所有跳过N个文档:

> db.book.find().skip(1)

MongoDB shell 还提供了以下方法来查询文档:

  • 要查询单个文档,请使用 db.collection.findOne()。

  • 要查询多个文档,请使用 db.collection.findOne()。

更新文档

MongoDB shell 提供 db.collection.update() 来更新集合中的文档:

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>, // Added in MongoDB 4.2
     let: <document> // Added in MongoDB 5.0
   }
)

参数解说明:

query:update的查询条件,类似sql update查询内where后面的。

update:update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的。

upsert:可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。

multi:可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

writeConcern:可选,抛出异常的级别。

let:可选。指定一个带有变量列表的文件。这允许你通过将变量与查询文本分开来提高命令的可读性

实例如下:

  • 操作更新 book 集合 _id 等于 xxx,likes 自增 N,设置字段:

> db.book.update(
    { _id: ObjectId("641c62a68718025b9b22b48c") },
    {
      $inc: { likes: 5 },
      $set: {
        title: "MongoDB 从入门到成神",
      }
    }
 )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
  • 操作更新 book 集合 匹配更新多个文档 type 等于 xxx,更新字段:

> db.book.update(
    { type: "literature"},
    {
      $set: {
        publishedDate: new Date()
      }
    },
   { multi: true }
 )
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
  • 操作更新 book 集合,若匹配条件不存在则新增文档:

db.book.update(
   { ttile: "Sqlite 从入门到放弃" },
   {
     $set: {
        title: "Sqlite 从入门到放弃",
        description: 'Sqlite 是一个关系型数据库',
        type: "literature",
        tags: ['sqlite',  'database',  'sql'],
        likes: 199,
        price: 48.88,
        publishedDate: new Date()
      }
   },
   {upsert: true}
)
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("6420172059c0fec3fb88c4a9")
})

更新操作符

操作符

格式

描述

$set

{ $set: { field: value } }

指定一个键并跟更新值,若键不存在则创建

$unset

{ $unset: { field: 1 } }

删除一个键

$inc

{ $inc: { field: value } }

对数值类型进行增减

$push

{ $push: { field: value } }

将数值追加数组中,若数组不存在则进行初始化

$pushAll

{ $pushAll: { field: value_arry } }

追加多个值到一个数组中

MongoDB shell 提供了以下方法来更新集合中的文档

  • 更新单个文档,使用 db.collection.updateOne()。

  • 更新多个文档,使用 db.collection.updateMany()。

  • 替换文档,使用 db.collection.replaceOne()。

删除文档

MongoDB 使用 remove() 函数是用来移除集合中的数据,语法如下:

db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     let: <document> // Added in MongoDB 5.0
   }
)

参数解释:

  • query:使用查询操作符指定删除标准。要删除一个集合中的所有文件,请传递一个空文件({})。

  • justOne:可选。要将删除限制在一个文件上,设置为true。如果省略,则使用默认值false,并删除符合删除条件的所有文件。

  • writeConcern:可选。一个表达写关注的文件。省略以使用默认的写关注。

  • collation:可选。指定操作中要使用的整理方式。

  • let:可选。指定一个带有变量列表的文档。这允许你通过将变量与查询文本分开来提高命令的可读性。

实例如下:

  • 删除 book 集合中 _id 等于 xxx 的文档:

> db.book.remove({ "_id": ObjectId("641c62a68718025b9b22b48c") } )
WriteResult({ "nRemoved" : 1 })
  • 删除 book 集合中所有的文档:

> db.book.remove({})
WriteResult({ "nRemoved" : 3 })
  • 删除 book 集合指定 type, 限制一个文档:

> db.book.remove({ "type": "literature"}, true)
WriteResult({ "nRemoved" : 1 })

MongoDB shell 提供了以下方法来删除集合中的文档:

  • 删除单个文档,使用 db.collection.deleteOne()。

  • 删除多个文档,使用 db.collection.deleteMany()

聚合

MongoDB 中聚合(aggregate)主要用于处理数据(如:平均值,求和等),并返回计算后的数据结果。

语法如下:

db.collection.aggregate([
  {
    <$stage1>
  },
  {
    <$stage2>
  }
  ...
])

实例如下:

  • 操作 book 集合中所有指定字段:

> db.book.aggregate(
    { $project : {
        title : 1 ,
        author : 1 ,
    }}
 )
{ "_id" : ObjectId("64202c9bd6e77a9446206630"), "title" : "Mysql 从入门到放弃", "author" : "mysql" }
{ "_id" : ObjectId("64202c9bd6e77a9446206631"), "title" : "Oracle 从入门到放弃" }
  • 操作 book 集合,匹配只当条件的文档,按 title 分组,统计 likes 合计:

db.book.aggregate([
    { $match : { price : { $gt : 50, $lte : 100 } } },
    { $group: { _id:  "$title", likes: { $sum: "$likes" } } }
 ])
{ "_id" : "Oracle 从入门到放弃", "likes" : 66 }
{ "_id" : "Mysql 从入门到放弃", "likes" : 99 }
  • 操作 book 集合,匹配条件的文档,将 tags 数组展开:

db.book.aggregate( [
    { $match : { price :  99.99} },
    { $unwind : "$tags" }
 ] )
{ "_id" : ObjectId("64202c9bd6e77a9446206631"), "title" : "Oracle 从入门到放弃", "description" : "Oracle 是一个关系型数据库", "type" : "literature", "tags" : "oracle", "likes" : 66, "price" : 99.99, "publishedDate" : ISODate("2023-03-26T11:29:31.545Z") }
{ "_id" : ObjectId("64202c9bd6e77a9446206631"), "title" : "Oracle 从入门到放弃", "description" : "Oracle 是一个关系型数据库", "type" : "literature", "tags" : "database", "likes" : 66, "price" : 99.99, "publishedDate" : ISODate("2023-03-26T11:29:31.545Z") }
{ "_id" : ObjectId("64202c9bd6e77a9446206631"), "title" : "Oracle 从入门到放弃", "description" : "Oracle 是一个关系型数据库", "type" : "literature", "tags" : "sql", "likes" : 66, "price" : 99.99, "publishedDate" : ISODate("2023-03-26T11:29:31.545Z") }

聚合框架中常用的操作:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。

  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。

  • $limit:用来限制MongoDB聚合管道返回的文档数。

  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。

  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。

  • $group:将集合中的文档分组,可用于统计结果。

  • $sort:将输入文档排序后输出。

  • $geoNear:输出接近某一地理位置的有序文档。

聚合的常用表达式:

表达式

描述

实例

$sum

计算总和。

db.collection.aggregate([{$group : {_id : "$by_field", num_tutorial : {$sum : "$likes"}}}])

$avg

计算平均值。

db.collection.aggregate([{$group : {_id : "$by_field", num_tutorial : {$avg : "$likes"}}}])

$min

获取集合中所有文档对应值得最小值。

db.collection.aggregate([{$group : {_id : "$by_field", num_tutorial : {$min : "$likes"}}}])

$max

获取集合中所有文档对应值得最大值。

db.collection.aggregate([{$group : {_id : "$by_field", num_tutorial : {$max : "$likes"}}}])

$push

将值加入一个数组中,不会判断是否有重复的值。

db.collection.aggregate([{$group : {_id : "$by_field", url : {$addToSet : "$url"}}}])

$addToSet

将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。

db.collection.aggregate([{$group : {_id : "$by_field", url : {$push: "$url"}}}])

$first

根据资源文档的排序获取第一个文档数据。

db.collection.aggregate([{$group : {_id : "$by_field", first_url : {$first : "$url"}}}])

$last

根据资源文档的排序获取最后一个文档数据。

db.collection.aggregate([{$group : {_id : "$by_field", last_url : {$last : "$url"}}}])

索引

索引通常能够极大的提高查询的效率,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。

语法

db.collection.createIndex(keys, options, commitQuorum)

参数解析:

  • keys:一个包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。对于字段的升序索引,指定一个值为1;对于降序索引,指定一个值为-1。 星号(*)不是有效的索引名称。

  • options:可选。一个包含一组控制创建索引的选项的文档。

  • commitQuorum:可选。包括主副本在内的有数据表决权的副本集成员的最小数量(即提交法定人数),在主副本将索引标记为就绪之前,必须报告成功的索引构建。有投票权的成员是指成员[n].votes大于0的任何副本集成员。

分类

  • 按照索引包含的字段数量,可以分为单键索引和组合索引(或复合索引)。

  • 按照索引字段的类型,可以分为主键索引和非主键索引。

  • 按照索引节点与物理记录的对应方式来分,可以分为聚簇索引和非聚簇索引,其中聚簇索引是指索引节点上直接包含了数据记录,而后者则仅仅包含一个指向数据记录的指针。

  • 按照索引的特性不同,又可以分为唯一索引、稀疏索引、文本索引、地理空间索引等。

单键、复合索引

  • 单键索引

我们经常使用标题(title),可为其设置单键索引,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可,在单键索引中,使用升序和降序并没有什么差别:

> db.book.createIndex({"title":1})
{
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}
  • 复合索引

复合索引是多字段组合成的索引,其字段顺序、字段的升降序对查询性能有直接影响,涉及索引需考虑查询场景;我们对 book 集合按 分类(type)、点赞数量创建一个符合索引:

> db.book.createIndex( {type: 1, likes: 1} )
{
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}

数组索引

数组索引也被称为多值索引(multikey index),当我们对数组型创建索引时,这个索引就是多个值的。

  • 多值索引

我们对数组字段标签(tags)设置索引:

> db.book.createIndex({tages : 1})
{
        "numIndexesBefore" : 3,
        "numIndexesAfter" : 4,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}
  • 符合多值索引

我们对 book 集合中类型(type)和标签(tags)设置复合多值索引:

> db.book.createIndex({type : 1, tages : 1})
{
        "numIndexesBefore" : 4,
        "numIndexesAfter" : 5,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}

唯一性约束

唯一性时比较有用的一种索引约束,比如订单的编号需要唯一,用于区分记录。

创建索引时,通过指定 unique=true 选项声明为唯一索引,代码如下:

> db.book.createIndex({ title: 1 }, { unique: true })
{
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}

注意:

  • 唯一性索引对于文档中缺失的字段,会使用null值代替,因此不允许存在多个文档缺失索引字段的情况。

  • 对于分片的集合,唯一性约束必须匹配分片规则。换句话说,为了保证全局的唯一性,分片键必须作为唯一性索引的前缀字段。

TTL索引

有时数据库的文档你只需要存一定的时候,之后就可以删除,MongoDB 提供了一种有效期做法:TTL(Time To Live)索引。TTL索引需要声明在一个日期类型的字段中,达到指定过期时间自动删除:

db.book.createIndex({
    publishedDate: 1
}, {
    name: "published_date",
    expireAfterSeconds: 3
})
{
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}

注意:

  • TL索引只能支持单个字段,并且必须是非_id字段。

  • TTL索引不能用于固定集合。

  • TTL索引无法保证及时的数据老化,MongoDB 会通过后台的TTL Monitor定时器来清理老化数据,典型的间隔时间是1分钟。当然如果在数据库负载过高的情况下,TTL的行为则会进一步受到影响。

  • TTL索引对于数据的清理仅仅使用了remove命令,这种方式并不是很高效。因此TTL Monitor在运行期间对系统CPU、磁盘都会造成一定的压力。相比之下,按日期分表的方式操作会更加高效。

查询索引

  • 查询所有索引

> db.book.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        ...
]
  • 查询索引大小

> db.col.totalIndexSize()
0

删除索引

  • 删除单个索引

> db.collection.dropIndexes( [ "a_1_b_1", "a_1", "a_1__id_-1" ] )
{ "nIndexesWas" : 5, "ok" : 1 }
  • 删除多个集合

> db.book.dropIndexes( ["title_1", "tags_1"] )
{ "nIndexesWas" : 3, "ok" : 1 }
  • 删除全部索引

> db.book.dropIndexes()
{
        "nIndexesWas" : 4,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : 1
}

猜你喜欢

转载自blog.csdn.net/qq_34272964/article/details/129463880
今日推荐