【笔记】MongoDB学习笔记

前言

MongoDB是一种面向文档的数据库管理系统,用C++等语言撰写而成,以解决应用程序开发社区中的大量现实问题。MongoDB由MongoDB Inc.(当时是10gen团队)于2007年10月开发,2009年2月首度推出,现以服务器端公共许可(SSPL)分发。(维基百科

MongoDB和其他数据库的区别

  • 数据库用database表示
  • 集合(也就是其他数据库的数据表table)用collection表示
  • 字段(也就是其他数据库的字段column)用field表示
  • MongoDB的命令区分大小写
  • MongoDB的命令末尾不需要分号

数据类型

  • MongoDB通过BSON(一种二进制的JSON)来存储数据
  • BSON数据类型
    • 可以在Shell中使用的数据类型
      • 字符串
      • 对象id
      • 布尔值
      • 数组
      • 32位整数
      • 64位整数
      • 64位浮点数
      • null
      • undefined
      • //i正则表达式
      • function(){}函数
    • 不可以在Shell中使用的数据类型
      • 符号
      • 二进制数
      • 最大/小值

对数据库的操作

切换(创建/使用)数据库

  • 无论是否存在指定数据库名的数据库,在执行use命令后都会进入到指定数据库名的数据库
    • 如果数据库名已存在,就进入到一个已存在的数据库进行操作
    • 如果数据库名不存在,在创建集合后会自动创建这个数据库,在没有创建集合之前仍然不会出现在所有数据库列表中

<database_name>:数据库名

1
use <database_name>

数据库的命名规则

  • 不能是空字符串
  • 不能包含空字符(\0
  • 不能包含空格(
  • 不能包含特殊字符:.\/$
  • 必须全部是小写字母
  • 最长为64字节

默认数据库

  • admin:存放所有用户和权限
  • local:在这个数据库中存储的数据在部署集群后不会被同步
  • config:存放分片的信息

删除当前数据库

  • 删除当前use的数据库
1
db.dropDatabase()

查看当前数据库

1
db

查看所有数据库

1
show databases
1
show dbs

对集合的操作

创建集合

显式创建

<collection_name>:集合名

1
db.createCollection(<collection_name>)

隐式创建

  • 直接在指定集合新增文档,集合就会自动被创建

<collection_name>:集合名
<key>:键
<value>:值

1
db.<collection_name>.insert({"<key>": "<value>"})
1
db.<collection_name>.insert({"<key_1>": "<value_1>", "<key_2>": "<value_2>"})

删除集合

1
db.<collection_name>.drop()

查看所有集合

1
show tables

对文档的操作

新增文档

  • 向指定集合中新增文档

  • 文档的内容是类似于JSON的BSON

  • 在新增文档时,_id字段是mongodb的默认主键,会自增,可以省略,也可以手动指定

    • _id字段虽然是从1开始自增的数值,但是数据类型是字符串类型的

新增单条文档

1
db.<collection_name>.insert({字段名: 字段值})
通过变量新增文档
1
2
变量名 = {字段名: 字段值}
db.<collection_name>.insert(变量名)

新增多条文档

1
db.<collection_name>.insertMany([{字段名1: 字段值1}, {字段名2: 字段值2}])

删除文档

删除所有符合条件的文档

1
db.<collection_name>.remove({查询条件字段名: "查询条件字段值"})

删除全部文档

1
db.<collection_name>.remove({})

修改文档

  • 修改操作的第一个参数是查询条件
  • 修改操作的第二个参数是修改后的文档
  • 修改操作的第三个参数是其他参数,没有其他参数时可以省略

修改单条符合条件的文档

  • 当查询到多条文档符合条件时,默认情况下只修改第一次符合条件的文档
覆盖修改
1
db.<collection_name>.update({查询条件字段名: "查询条件字段值"}, {需要被修改的字段名: "修改后的字段值"})
局部修改
  • 通过$set:指定单独修改字段
1
db.<collection_name>.update({查询条件字段名: "查询条件字段值"}, {$set: {需要被修改的字段名: "修改后的字段值"}})
1
db.<collection_name>.update({查询条件字段名: "查询条件字段值"}, {$set: {需要被修改的字段名1: "修改后的字段值1"}, $set: {需要被修改的字段名2: "修改后的字段值2"}})
字段值自增

1:自增步长

1
db.<collection_name>.update({查询条件字段名: "查询条件字段值"}, {$inc: {需要被修改的字段名: NumberInt(1)}})

修改多条符合条件的文档

  • 通过{multi:true}修改全部匹配到的文档
覆盖修改
1
db.<collection_name>.update({查询条件字段名: "查询条件字段值"}, {需要被修改的字段名: "修改后的字段值"}, {multi: true})
局部修改
  • 通过$set:指定单独修改字段
1
db.<collection_name>.update({查询条件字段名: "查询条件字段值"}, {$set: {需要被修改的字段名: "修改后的字段值"}})
1
db.<collection_name>.update({查询条件字段名: "查询条件字段值"}, {$set: {需要被修改的字段名1: "修改后的字段值1"}, $set: {需要被修改的字段名2: "修改后的字段值2"}})

查询文档

查询所有文档

1
db.<collection_name>.find()
1
db.<collection_name>.find({})

查询符合条件的文档

完全匹配
  • 查询操作的第一个参数表示查询的条件
查询符合条件的文档的多条文档
1
db.<collection_name>.find({查询条件字段名: "查询条件字段值"})
1
db.<collection_name>.find({查询条件字段名1: "查询条件字段值1", 查询条件字段名2: "查询条件字段值2"})
查询符合条件的文档的单条文档
1
db.<collection_name>.findOne({查询条件字段名: "查询条件字段值"})
1
db.<collection_name>.findOne({查询条件字段名1: "查询条件字段值1", 查询条件字段名2: "查询条件字段值2"})
正则匹配
1
db.<collection_name>.find({查询条件字段名: /正则表达式/})
比较运算符

<num>:数值

$gt:大于
$gte:大于等于
$lt:小于
$lte:小于等于
$eq:等于
$ne:不等于

1
2
3
4
5
6
7
8
db.<collection_name>.find({"查询条件字段名": {$gt: NumberInt(<num>)}})
db.<collection_name>.find({"查询条件字段名": {$gte: NumberInt(<num>)}})
db.<collection_name>.find({"查询条件字段名": {$lt: NumberInt(<num>)}})
db.<collection_name>.find({"查询条件字段名": {$lte: NumberInt(<num>)}})
db.<collection_name>.find({"查询条件字段名": {$eq: NumberInt(<num>)}})
db.<collection_name>.find({"查询条件字段名": {$ne: NumberInt(<num>)}})
db.<collection_name>.find({"查询条件字段名": {$lt: NumberInt(<num>),$gte: NumberInt(<num>)}})
db.<collection_name>.find({"查询条件字段名": {$gt: NumberInt(<num>),$lte: NumberInt(<num>)}})
成员运算符

$in:包含
$nin:不包含

1
2
db.<collection_name>.find({"查询条件字段名": {$in: ["查询条件字段值1", "查询条件字段值2"]}})
db.<collection_name>.find({"查询条件字段名": {$nin: ["查询条件字段值1", "查询条件字段值2"]}})
逻辑运算符

$and:并且
$or:或者

1
2
db.<collection_name>.find({$and: [{"查询条件字段名": "查询条件字段值"}]})
db.<collection_name>.find({or: [{"查询条件字段名": "查询条件字段值"}]})

查询结果的筛选条件

  • 查询操作的第二个参数表示查询结果的筛选条件
添加查询结果的筛选条件
1
db.<collection_name>.find({}, {查询结果字段名: 1})
1
db.<collection_name>.find({}, {查询结果字段名1: 1, 查询结果字段名2: 1})
排除查询结果的筛选条件
1
db.<collection_name>.find({}, {查询结果字段名: 0})
1
db.<collection_name>.find({}, {查询结果字段名1: 0, 查询结果字段名2: 0})
混合条件
1
db.<collection_name>.find({}, {查询结果字段名1: 1, 查询结果字段名2: 0})

查询文档总数

查询所有文档总数
1
db.<collection_name>.count()
1
db.<collection_name>.count({})
查询符合条件的文档总数
1
db.<collection_name>.count({查询条件字段名: "查询条件字段值"})

查询指定数量的文档

1
db.<collection_name>.find().limit(1)

跳过指定数量的文档

1
db.<collection_name>.find().skip(1)

分页查询

  • 通过查询指定数量和跳过指定数量的文档实现分页
1
db.<collection_name>.find().skip((页数-1)*页内数据总数).limit(页内数据总数)

排序查询结果

升序
1
db.<collection_name>.find().sort({需要排序的字段名: 1})
1
db.<collection_name>.find().sort({需要排序的字段名1: 1, 需要排序的字段名2: 1})
降序
1
db.<collection_name>.find().sort({需要排序的字段名: -1})
1
db.<collection_name>.find().sort({需要排序的字段名1: -1, 需要排序的字段名2: -1})
混合排序
1
db.<collection_name>.find().sort({需要排序的字段名1: 1, 需要排序的字段名2: -1})

查询结果转换为JSON

1
db.<collection_name>.find().pretty()

高级查询

  • 将查询的结果重新整理为新的数据格式

分组查询(GroupBy)

输入表的字段名的字段去重,得到新的一组数据,数据的字段名被定义为输出表中的字段名

1
db.<collection_name>.aggregate({"$group": {"_id": {"输出表中的字段名": "$输入表的字段名"}}})

如果是嵌套的字段作为输入表的字段名

1
db.<collection_name>.aggregate({"$group": {"_id": {"输出表中的字段名": "$输入表的字段名.输入表的子字段名"}}})

输入表的字段名1输入表的字段名2作为联合唯一键,得到新的一组数据

1
db.<collection_name>.aggregate({"$group": {"_id": {"输出表中的字段名1": "$输入表的字段名1", "输出表中的字段名2": "$输入表的字段名2"}}})

捕获异常

  • mongodb在执行批量操作时不会因为单条数据的操作失败而回滚,只能通过捕获异常来判断是否有执行失败的操作
1
2
3
4
5
try {
db.<collection_name>.insert({...})
} catch (e) {
print(e)
}

对索引的操作

  • 通过已经创建了索引的字段进行查询时,效率会更高
  • 如果查询的结果字段只有已经创建了索引的字段,那么MongoDB就直接从索引中获取数据,而不会再从集合中获取数据

查询索引

  • 查询当前数据库的指定集合的索引
1
db.<collection_name>.getIndexes()

新增索引

  • 在当前数据库的指定集合上创建索引
  • 每个集合中的_id字段默认就有升序索引,这个索引既不需要手动创建,也不会被删除

单字段索引

1:升序索引
-1:降序索引

1
db.<collection_name>.createIndex({需要创建索引的字段名: 1})

升序索引名默认为被创建索引的字段名_1

1
db.<collection_name>.createIndex({需要创建索引的字段名: -1})

降序索引名默认为被创建索引的字段名_-1

多字段索引(复合索引)

1
db.<collection_name>.createIndex({需要创建索引的字段名1: 1, 需要创建索引的字段名2: -1})

索引名默认为被创建索引的字段名1_1_被创建索引的字段名2_-1

删除索引

删除单个索引

通过索引名删除索引
1
db.<collection_name>.dropIndex(索引名)
通过规则删除索引
1
db.<collection_name>.dropIndex({需要删除索引的字段名: -1})

删除所有索引

  • 删除除了_id以外的所有字段的索引
1
db.<collection_name>.dropIndexes()

查询性能

1
db.<collection_name>.find().explain()

queryPlainner.winningPlain.stage

COLLSCAN:全局扫描,没有使用索引
FETCH:抓取,使用索引扫描

用户

  • 不同的角色有不同的权限
  • 在创建用户时,通过为用户赋予角色,而控制用户权限
角色名 权限
read 可以读取指定数据库中的任何数据
readWrite 可以读写指定数据库中的任何数据
readAnyDatabase 可以读取所有数据库中的任何数据
readWriteAnyDatabase 可以读写所有数据库中的任何数据
userAdmin 可以在指定数据库创建和修改用户
userAdminAnyDatabase 可以在任何数据库创建和修改用户
dbAdmin 可以读取指定数据库,以及对数据库进行清理、压缩、获取统计信息、执行检查等操作
dbAdminAnyDatabase 可以读取所有数据库,以及对数据库进行清理、压缩、获取统计信息、执行检查等操作
clusterAdmin 可以对整个集群进行管理操作
restore 可以还原数据库的数据
backup 可以备份和还原数据库的数据
root 拥有所有权限

新增用户

1
2
use admin
db.createUser({user:"用户名",pwd:"密码",roles:["角色名1", "角色名2"]})

创建超级管理员

1
2
use admin
db.createUser({user:"用户名",pwd:"密码",roles:["root"]})

创建普通管理员

1
2
use admin
db.createUser({user: "用户名", pwd: "密码", roles: {role: "userAdminAnyDatabase",db: "admin"}})

创建普通用户

1
2
use 用户可以操作的数据库
db.createUser({user: "用户名", pwd: "密码", roles: {role: "readWrite", db: "用户可以操作的数据库"}})

删除用户

1
db.dropuser("用户名")

修改用户

修改用户密码

1
db.changeUserPassword("用户名", "新密码")

查看用户

查看所有用户

1
db.system.users.find()

登录

1
db.auth("用户名", "密码")

验证成功返回1
验证失败返回0,提示:Error: Authentication failed

开启MongoDB的认证

1
mongodb --auth

完成

参考文献

程序媛
掘金——古拉里
掘金——六个周
CSDN——kalrry
哔哩哔哩——图灵学院教程
哔哩哔哩——黑马程序员
CSDN——lff0305