MongoDB 基础教程
工作中的项目用到 MongoDB 的地方还是不少的,只是前几个月都比较忙碌,一直没腾出时间好好梳理一下。这两周稍微轻松些了,就决定把 MongoDB 这块知识过一遍,也方便以后参考(实在讨厌各大博客网站的转载机制,劣质无用的文章被转载的到处都是,真正遇到问题时,想要找到一篇具有参考性的文章实在太难)。由于工作中暂无 MongoDB 集群的使用场景,因此本文暂未整理分片集群这块的知识(标记为 TODO
,或许日后会补充)。
NoSQL 简介
NoSQL,指的是非关系型的数据库。NoSQL 是 Not Only SQL 的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。NoSQL 通常用于超大规模数据的存储(如谷歌或 Facebook 每天为他们的用户收集万亿比特的数据),这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
NoSQL 优缺点
优点:
- 高可扩展性
- 分布式计算
- 低成本
- 架构的灵活性,半结构化数据
- 没有复杂的关系
缺点:
- 没有标准化
- 有限的查询功能(到目前为止)
- 最终一致是不直观的程序
RDBMS vs NoSQL
关系型数据库(RDBMS)与非关系型数据库(NoSQL)对比:
对比项 | RDBMS | NoSQL |
---|---|---|
存储格式 | 表格式,行和列 | 文档、键值对、图结构 |
存储规范 | 规范性,避免重复 | 鼓励冗余 |
存储扩展 | 纵向扩展(横向扩展有限) | 横向扩展,分布式 |
查询方式 | 结构化查询 | 非结构化查询语言SQL |
事务 | 支持事务 | 不支持事务一致性 |
性能 | 读写性能差 | 读写性能高 |
成本 | 成本高 | 简单易部署,开源,成本低 |
存储方式 | 数据主要存储在磁盘中 | 数据主要存储在内存中(部分可以持久化到磁盘) |
建表原则 | 依靠关系模型构建关联 | 数据模型比较简单,用K/V的形式来存储数据 |
MongoDB 简介
MongoDB 是由 C++
语言编写的,是一个基于分布式文件存储的开源非关系型数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
MongoDB 使用 BSON(Binary JSON)对象来存储,与 JSON 格式的键值对(key/value)类似,字段值可以包含其他文档,数组及文档数组。支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系型数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
MongoDB 主要特点
- MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。
- 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName=“Sameer”,Address=“8 Gandhi Road”)来实现更快的排序。
- 你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。
- 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。
- Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
- MongoDB 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
- MongoDB 中的Map/reduce主要是用来对数据进行批量处理和聚合操作。
- Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。
- Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
- GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
- MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
- MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
- MongoDB安装简单。
MongoDB 数据类型
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Arrays | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
MongoDB 支持语言
下载与安装
Windows 环境
双击可执行文件 .msi
,进行安装(基本上下一步即可)。
推荐选择自定义安装:
推荐取消默认的 Install MongoDB Compass
安装。
MongoDB 配置:
-
环境变量
编辑系统变量
Path
并添加 MongoDB 的 bin 目录位置。例如:A:\MongoDB\Server\5.0\bin
-
创建数据库文件的存放位置
创建文件夹
[MongoDB]\data\db
。这是因为 MongoDB 服务在启动之前必须创建数据库文件的存放文件夹,否则命令不会自动创建,且服务无法启动成功。
-
启动 MongoDB 服务
cmd
命令进入安装目录[MongoDB]\data\bin
位置,执行如下命令:A:\MongoDB\Server\5.0\bin> mongod --dbpath A:\MongoDB\Server\5.0\data\db
浏览器访问:http://127.0.0.1:27017,如果出现如下信息,则表示配置成功且服务已启动:
It looks like you are trying to access MongoDB over HTTP on the native driver port.
-
配置本地 MongoDB 服务
创建文件夹
[MongoDB]\data\log
,用于存放日志文件。创建配置文件
[MongoDB]\mongo.config
:dbpath=A:\MongoDB\Server\5.0\data\db logpath=A:\MongoDB\Server\5.0\data\log\mongo.log
使用管理员角色执行如下命令:
# 停止已启动的MongoDB服务 net stop MongoDB # 移除MongoDB服务 sc delete MongoDB # 安装MongoDB服务 mongod -dbpath "A:\MongoDB\Server\5.0\data\db" -logpath "A:\MongoDB\Server\5.0\data\log\mongo.log" -install -serviceName "MongoDB" # 启动MongoDB服务 net start MongoDB
浏览器访问:http://127.0.0.1:27017
客户端连接:
A:\MongoDB\Server\5.0\bin> mongo.exe
Linux 环境
-
卸载删除
# 停止服务 ps -ef | grep mongo kill -9 xxx net stop mongodb sudo yum erase $(rpm -qa | grep mongodb-org) #卸载MongoDB sudo rm -r /var/log/mongodb #删除日志文件 sudo rm -r /var/lib/mongo #删除数据文件
-
安装
配置 yum 源:
cd /etc/yum.repos.d vi mongodb-org-5.0.repo # 版本选择可前往 https://repo.mongodb.org 进行查看。
编辑如下内容(版本号视个人需要而定):
[mongodb-org-5.0] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/7Server/mongodb-org/5.0/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-5.0.asc
提示:具体版本,可前往源地址进行查看选择:https://repo.mongodb.org
执行安装:
yum install -y mongodb-org
修改配置:
vim /etc/mongod.conf # network interfaces net: port: 27017 bindIp: 0.0.0.0 # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.
基本命令:
systemctl start mongod.service # 启动 systemctl status mongod.service # 查看状态 systemctl stop mongod.service # 停止 systemctl enable mongod.service # 自启
测试连接:
mongo 127.0.0.1:27017 # 如果是默认IP端口,可以不指定
权限控制:
use admin # 其他数据库也类似 switched to db admin db.createUser({ user:"admin", pwd:"123456", roles:["root"] }) Successfully added user: { "user" : "admin", "roles" : [ "root" ] } db.auth("admin", "123456") 1 exit bye mongo -u root -p 123456 # 账号登录
启用身份验证:
vi /etc/mongod.conf security: authorization: enabled # disable or enabled
-
问题排查
-
MongoDB 服务启动失败,可以使用
journalctl -xe
命令跟踪更加详细的信息,通常是由于以下几种原因导致的:- mongod.conf 配置内容或语法错误。
- 日志访问权限不足。
- 锁定
-
如果服务器本地可以访问 MongoDB,但远程访问失败,请检查:
- 检查配置文件
/etc/mongod.conf
IP 是否放开、是否允许远程访问,以及访问账号密钥信息。 - 云服务器需注意配置安全组规则。
- 如已开启防火墙,需添放开对应端口。
- 检查配置文件
-
命令提示
# 查看与修改 vi /etc/mongod.conf # MongoDB 配置文件 cat /usr/lib/systemd/system/mongod.service # MongoDB 服务 # 权限或mongodb锁文件 sudo chown -Rc mongodb. /var/log/mongodb sudo chown -Rc mongodb. /var/lib/mongo rm -rf /var/lib/mongo/mongod.lock rm -rf /tmp/mongodb-27017.sock # 防火墙 firewall-cmd --state # 查看防火墙状态 systemctl stop firewalld.service # 关闭防火墙 systemctl start firewalld.service # 开启防火墙 firewall-cmd --add-port=27017/tcp --permanent # 防火墙放开指定端口(永久) firewall-cmd --zone=public --list-ports # 查看防火墙已开放端口 firewall-cmd --reload # 防火墙配置重新载入
配置参考:https://docs.mongodb.com/manual/reference/configuration-options
-
MongoDB GUI
术语与概念
SQL 数据库与 MongoDB 数据库术语及概念的对比:
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
数据库
一个 mongodb 中可以建立多个数据库。MongoDB的默认数据库为 db
,该数据库存储在data目录中,这一点我们在安装配置时已有提及。
MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
> show dbs # 显示所有数据列表
admin 0.000GB
config 0.000GB
local 0.000GB
> db # 显示当前数据库对象或集合
test
> use local # 切换到指定数据库
switched to db local
MongoDB 默认有三个数据库:
- admin:从权限的角度来看,这是 root 数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
- local:这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
- config: 当 Mongo 用于分片设置时,config 数据库在内部使用,用于保存分片的相关信息。
文档
文档是一组键值对(即 BSON),示例:
{"site":"www.chinmoku.cc", "author":"Chinmoku"}
RDBMS 与 MongoDB 术语对比:
RDBMS | MongoDB |
---|---|
数据库 | 数据库 |
表格 | 集合 |
行 | 文档 |
列 | 字段 |
表联合 | 嵌入文档 |
主键 | 主键(MongoDB 提供了 key 为 _id) |
注意:
- 文档中的键值对是有序的。
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
- MongoDB 区分类型和大小写。
- MongoDB 的文档不能有重复的键。
- 文档的键是字符串,除少数例外情况,键可以使用任意 UTF-8 字符。
文档键命名规范:
- 键不能含有空字符。这个字符用来表示键的结尾。
.
和$
有特别的意义,只有在特定环境下才能使用。- 以下划线开头的键是保留的(不是严格要求的)。
集合
集合就是 MongoDB 文档组,类似于 RDBMS 中的表。集合存在于数据库中,集合没有固定的结构。
集合的合法性:
- 集合名不能是空字符串。
- 集合名不能含有
\0
空字符,这个字符表示集合名的结尾。 - 集合名不能以
system.
开头,这是为系统集合保留的前缀。 - 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。
Capped Collections
Capped collections 就是固定大小的 collection,它是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能和标准的 collection 不同,你必须要显式的创建一个capped collection,指定一个 collection 的大小,单位是字节。collection 的数据存储空间值提前分配的。
Capped collections 可以按照文档的插入顺序保存到集合中,而且这些文档在磁盘上存放位置也是按照插入顺序来保存的,所以当我们更新 Capped collections 中文档的时候,更新后的文档不可以超过之前文档的大小,这样话就可以确保所有文档在磁盘上的位置一直保持不变。
由于 Capped collection 是按照文档的插入顺序而不是使用索引确定插入位置,这样的话可以提高增添数据的效率。MongoDB 的操作日志文件 oplog.rs 就是利用 Capped Collection 来实现的。
要注意的是指定的存储大小包含了数据库的头信息。
db.createCollection("mycoll", {capped:true, size:100000})
元数据
在 MongoDB 数据库中命名空间 <dbname>.system.*
是包含多种系统信息的特殊集合(Collection),如下:
集合命名空间 | 描述 |
---|---|
dbname.system.namespaces | 列出所有名字空间。 |
dbname.system.indexes | 列出所有索引。 |
dbname.system.profile | 包含数据库概要(profile)信息。 |
dbname.system.users | 列出所有可访问数据库的用户。 |
dbname.local.sources | 包含复制对端(slave)的服务器信息和状态。 |
ObjectId
ObjectId 类似唯一主键,可以很快的去生成和排序,它包含 12 个字节,其含义如下:
- 前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时。
- 接下来的 3 个字节是机器标识码。
- 紧接的两个字节由进程 id 组成 PID。
- 最后三个字节是随机数。
使用方式:
var newObject = ObjectId()
newObject.getTimestamp()
newObject.str
时间与字符串
-
BSON 字符串
BSON 字符串都是 UTF-8 编码。
-
时间戳
BSON 有一个特殊的时间戳类型用于 MongoDB 内部使用,与普通的日期类型不相关。
在单个 mongod 实例中,时间戳值通常是唯一的。
在复制集中,oplog 有一个 ts 字段。这个字段中的值使用 BSON 时间戳表示了操作时间。
BSON 时间戳类型主要用于 MongoDB 内部使用。
-
日期
表示当前距离 Unix 新纪元(1970年1月1日)的毫秒数。日期类型是有符号的,负数表示 1970 年之前的日期,创建及使用方式如下:
var mydate = new Date() typeof mydate mydate.toString() Date()
这样创建的时间是日期类型,可以使用 JS 中的 Date 类型的方法。
基本操作
数据库操作
-
创建连接
# 连接实例: mongodb://root:123456@127.0.0.1/test
更多 MongoDB 连接配置,参考:https://www.runoob.com/mongodb/mongodb-connections.html
-
创建或切换数据库
# 如果不存在,则创建,如果已存在,则切换 use mytest # 查看所有数据库(当创建的数据库没有数据时,不会显示) show dbs # 插入一条数据 db.col1.insert({"name":"Chinmoku"}) # 再次查询数据库列表 show dbs
-
删除数据库
use mytest db.dropDatabase()
集合与文档操作
-
创建集合
# 创建集合 db.createCollection("test") # 查看所有集合 show collections # 查看所有集合(方式二) show tables # 创建固定集合 db.createCollection("col2",{capped:true,autoIndexId:true,size:6142800,max:10000}) # 集合大小:6142800B,最大文档个数:10000
在 MongoDB 中,其实不需要显式创建集合,在插入文档时,MongoDB 就会自动创建集合。
-
删除集合
# db.collection.drop(),返回布尔值 db.col2.drop()
-
文档基本操作
# 插入文档 db.col.insert({title: 'Telephone Book', user: 'Jason',mobile: '138****2573',site: 'https://www.jason.com',label: ['classmate', 'friend'],description: ''}) db.col.find() # 查看文档内容 # 也可以将数据定义为变量,然后插入该变量 jason_document=({title: 'Telephone Book', user: 'Jason',mobile: '138****2573',site: 'https://www.jason.com',label: ['classmate', 'friend'],description: ''}) db.col.insert(jason_document) # v3.2版本之后新增了insertOne和insertMany方法 db.col2.insertOne({"name": "Lily"}) db.col2.insertMany([{"name": "Charles"},{"name": "James"}])
save 方法也可以创建文档。
-
更新文档
# 参数(1.筛选条件,2.更新内容,3.***,4.***) db.col.update({'title':'Telephone Book'},{$set:{'title':'Telephone Book: Jason'}}) # 查询标题为Telephone Book的数据,并更新标题 # 同时更新多条文档内容 db.col.update({'user':'Jason'},{$set:{'title':'Telephone Book: Jason'}},{multi:true}) # save(如果指定了 _id 字段,则更新对应文档,如果未指定,则新增文档) db.col.save({"_id" : ObjectId("61c9ad7bba2a467651726dba"),title: 'Telephone Book: Bill', user: 'Bill',mobile: '187****0966',site: 'https://www.bill.com',label: ['classmate'],description: ''}) db.col.find() # 查询并格式化显示
使用 save 方法更新文档时,文档内所有字段都会被更新,即 save 中未指定字段会被移除,save 指定但数据库不存在字段会被新增。
-
删除文档
# 删除指定数据 db.col.remove({'user':'Jason'}) # 删除所有 db.col.remove({})
-
查询文档
# 查询所有 db.col.find() # 查询并返回指定的键 db.col.find({},{"title":1,_id:0}) db.col.find() # 查询并格式化显示 db.col.find().pretty() # 查询一条 db.col.findOne()
比较查询:
操作 格式 示例 等于 {<key>:<value>}
db.col.find({“title”:“John”}) 小于 {<key>:{$lt:<value>}}
db.col.find({“age”:{$lt:18}}) 小于等于 {<key>:{$lte:<value>}}
db.col.find({“age”:{$lte:18}}) 大于 {<key>:{$gt:<value>}}
db.col.find({“age”:{$gt:18}}) 大于等于 {<key>:{$gte:<value>}}
db.col.find({“age”:{$gte:18}}) 不等于 {<key>:{$ne:<value>}}
db.col.find({“age”:{$ne:18}}) 这些比较查询语句,类似于关系型数据库中的
select * from col where age > 18;
。AND 和 OR:
# AND db.col.find({key1:value1, key2:value2}) # OR db.col.find({$or:[{key1: value1},{key2:value2}]}) # AND和OR联合使用 db.col.find({"site": "https://www.jason.com", $or: [{"user": "Jason"},{"age": {$gt:18}}]})
进阶操作
$type
使用示例:
# 查询title类型为string的数据
db.col.find({"title" : {$type : 2}})
# 等价于
db.col.find({"title" : {$type : 'string'}})
limit 和 skip
# 查询2条记录
db.col.find({},{"user":1,_id:0}).limit(2)
# 跳过1条数,并查询其后续的2条记录
db.col.find({},{"user":1,_id:0}).limit(2).skip(1)
排序
# 排序使用1和-1来分别表示正序和倒叙
db.col.find({},{"user":1,_id:0}).sort({"age":-1})
索引
# 根据键名user按顺序创建索引,1为升序,-1为降序
db.col.createIndex({"user":-1})
# 复合索引
db.col.createIndex({"title":1,"description":-1})
# 查看集合索引
db.col.getIndexes()
# 查看集合索引大小
db.col.totalIndexSize()
# 删除所有集合索引
db.col.dropIndexes()
# 删除集合指定索引
db.col.dropIndex("myindex")
创建索引还可以接受许多参数,如索引名称、是否唯一、设置过期时间等,详情可自行参考官方文档。
聚合
db.mypost.aggregate([{$group : {_id : "$author", post_count : {$sum : 1}}}])
# 类似于如下SQL
select author, count(*) as post_count from mypost group by author
-
管道:
在此处的示例中,
$group
是 MongoDB 管道的一种,MongoDB 的聚合管道将 MongoDB 文档在一个管道处理完毕后将结果传递给下一个管道处理,并且管道操作是可以重复的。常用管道操作符:
- $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
- match 使用 MongoDB 的标准查询操作。
- $limit:用来限制 MongoDB 聚合管道返回的文档数。
- $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
- $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
- $group:将集合中的文档分组,可用于统计结果。
- $sort:将输入文档排序后输出。
- $geoNear:输出接近某一地理位置的有序文档。
-
表达式:
此处示例中的
$sum
即是表示聚合操作的表达式。常用表达式:
- $sum:计算总和。
- $avg:计算平均值
- $min:获取集合中所有文档对应值得最小值。
- $max:获取集合中所有文档对应值得最大值。
- $push:将值加入一个数组中,不会判断是否有重复的值。
- $addToSet:将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。
- $first:根据资源文档的排序获取第一个文档数据。
- $last:根据资源文档的排序获取最后一个文档数据
复制(副本集)
MongoDB 复制是将数据同步在多个服务器的过程。复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。复制还允许您从硬件故障和服务中断中恢复数据。
MongoDB 复制原理:
MongoDB 复制至少需要两个节点,其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。
主节点记录在其上的所有操作 oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
MongoDB 复制结构图如下所示:
副本集具有如下特征:
- N 个节点的集群
- 任何节点可作为主节点
- 所有写入操作都在主节点上
- 自动故障转移
- 自动恢复
副本集设置:
# 启动一个名为rs0的MongoDB实例
mongod --port 27017 --dbpath "A:\MongoDB\Server\5.0\data" --replSet rs0
# 客户端连接并启动一个新的副本集
rs.initiate()
# 查看副本集配置
rs.conf()
# 查看副本集状态
rs.status()
添加副本集成员:
# 副本集添加成员
rs.add("192.168.0.101:27017")
# 判断当前运行的Mongo服务是否为主节点
db.isMaster()
MongoDB 中你只能通过主节点将 Mongo 服务添加到副本集中,并且,MongoDB 的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点。
分片
MongoDB 中存在一种分片技术,它可以通过在多台机器上分割数据的方式,来使得数据库系统能存储和处理更多的数据或提高读写吞吐量。
分片结构集群部署图例:
组件说明:
- Shard:用于存储实际的数据块,实际生产环境中一个 shard server 角色可由几台机器组个一个 replica set 承担,防止主机单点故障。
- Config Servers:mongod 实例,存储了整个 ClusterMetadata,其中包括 chunk 信息。
- Query Routers:前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。
[❗TODO]{.label .danger} 未完待补充
备份与恢复
# 数据备份,语法:mongodump -h <hostname><:port> -d dbname -o <path>
# 不指定参数,则连接本地27017端口服务,默认备份到目录 [mongodb]/bin/dump/ 中
mongodump
# 备份恢复,语法:mongorestore -h <hostname><:port> -d dbname <path>
# 不指定参数,则连接本地27017端口服务,默认从目录 [mongodb]/bin/dump/ 中获取备份文件
mongorestore
监控
mongostat
是 MongoDB 自带的状态检测工具,在命令行下使用。它会间隔固定时间获取 MongoDB 的当前运行状态,并输出。
使用方式:
mongostat # 无密码监控默认数据库
mongostat -uroot -p123456 --authenticationDatabase=admin
如提示 command serverStatus requires authentication,那么多半是因为 MongoDB 需要登录权限,详情可通过命令
mongostat --help
查看。
mongotop
也是 MongoDB 下的一个内置工具,mongotop 提供了一个方法,用来跟踪一个 MongoDB 的实例,查看哪些大量的时间花费在读取和写入数据。 mongotop 提供每个集合的水平的统计数据。默认情况下,mongotop 返回值的每一秒。
使用方式:
mongotop # 无密码监控默认数据库
mongotop -uroot -p123456 --authenticationDatabase=admin
mongotop -uroot -p123456 --authenticationDatabase=admin --lock # 监控各个数据库锁使用情况
API
Java API
此处 MongoDB Java API 以 SpringBoot 框架作为示例。
准备工作:
-
使用 SpringInitializer 创建一个测试项目。
-
配置依赖包。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
-
启动文件配置:
spring: data: mongodb: uri: "mongodb://localhost:27017/test" # 如未设置则不需要指定用户名及密码 # username: # password:
-
创建用于测试的实体类:
@Data public class User { // id会被映射为mongodb文档的主键 private String id; private String name; private int age; }
基础增删改查:
-
创建接口:
public interface UserService { User insert(User user); User save(User user); User update(User user); List<User> findAll(); boolean remove(User user); }
-
实现类:
@Service public class UserServiceImpl implements UserService { @Autowired private MongoTemplate mongoTemplate; @Override public User insert(User user) { return this.mongoTemplate.insert(user); } @Override public User save(User user) { return this.mongoTemplate.save(user); } @Override public User update(User user) { return this.mongoTemplate.save(user); } @Override public List<User> findAll() { return this.mongoTemplate.findAll(User.class); } @Override public boolean remove(User user) { DeleteResult result = this.mongoTemplate.remove(user); return result.getDeletedCount() > 0; } }
-
提供 API 访问:
@RestController public class UserController { @Autowired private UserService userService; @GetMapping("/list") public List<User> findAll() { return this.userService.findAll(); } @PostMapping("/insert") public User insert(User user) { return this.userService.insert(user); } @PostMapping("/save") public User save(User user) { return this.userService.save(user); } @PostMapping("/update") public User update(User user) { return this.userService.update(user); } @PostMapping("/remove") public boolean remove(User user) { return this.userService.remove(user); } }
-
测试发送请求:
### 添加用户 POST http://localhost:8080/insert?name=Lily&age=21 Accept: application/json ### POST http://localhost:8080/insert?name=Mike&age=26 Accept: application/json ### POST http://localhost:8080/insert?name=Jason&age=27 Accept: application/json ### POST http://localhost:8080/insert?name=Philips&age=14 Accept: application/json ### 添加 POST http://localhost:8080/save?name=Jill&age=28 Accept: application/json ### 修改 POST http://localhost:8080/save?name=Jill&age=28&id=61caf27055120f6b62234917 Accept: application/json ### 修改 POST http://localhost:8080/update?name=Tom&age=33&id=61caf27055120f6b62234917 Accept: application/json ### 查询列表 GET http://localhost:8080/list Accept: application/json
扩展查询:
// 单一条件查询示例
@Override
public User queryById(String id) {
Criteria criteria = Criteria.where("id").is(id);
Query query = Query.query(criteria);
return this.mongoTemplate.findOne(query, User.class); // 返回一条
}
// 符合条件查询示例
@Override
public List<User> queryByCondition(int age, String name) {
Criteria criteria = new Criteria();
criteria.orOperator(Criteria.where("age").gt(age), Criteria.where("name").is(name));
Query query = Query.query(criteria);
// 排序
Sort sort = Sort.by(new Sort.Order(Sort.Direction.DESC, "id"));
query.with(sort);
return this.mongoTemplate.find(query, User.class); // 返回多条
}
// 分页查询
@Override
public List<User> queryWithPage(int index, int limit) {
Query query = new Query();
query.skip(index).limit(limit);// 从下标为index开始查询接下来的limit条数据
return this.mongoTemplate.find(query, User.class);
}
// 模糊查询
@Override
public List<User> like(String chars) {
Query query = new Query(Criteria.where("name").regex(chars));// 查询name中包含指定字符的数据
return this.mongoTemplate.find(query, User.class);
}
// 查询并删除
@Override
public boolean queryToRemove(String id) {
Query query = new Query(Criteria.where("id").is(id));
DeleteResult result = this.mongoTemplate.remove(query);
return result.getDeletedCount() > 0;
}
更多 Java API 用法,请查询 spring-boot-starter-data-mongodb 文档。
Python API
-
安装 pymongo 连接工具:
python3 -m pip3 install pymongo # 如需更新,执行如下命令: python3 -m pip3 install --upgrade pymongo
-
数据库与集合操作:
#!/usr/bin/python3 import pymongo # 建立连接 myclient = pymongo.MongoClient("mongodb://localhost:27017/") # 创建数据库 mydb = myclient["test"] # 查询数据库列表 dblist = myclient.list_database_names() # dblist = myclient.database_names() if "test" in dblist: print("数据库已存在!") # 创建集合 mydb = myclient["test"] mycol = mydb["col"] # 查询集合列表 collist = mydb.list_collection_names() if "col" in collist: print("集合已存在!")
-
增删改查
新增:
# 插入一条数据 mydict = { "name": "Chinmoku", "site": "https://www.chinmoku.cc" } x = mycol.insert_one(mydict) print(x.inserted_id) # 文档数据ID # 插入多条数据 mylist = [ { "name": "Facebook", "url": "https://www.facebook.com" }, { "name": "知乎", "url": "https://www.zhihu.com" }, { "name": "Github", "url": "https://www.github.com" } ] x = mycol.insert_many(mylist) print(x.inserted_ids) # 也可以指定ID mylist = [ { "_id": 1, "name": "百度", "url": "https://www.baidu.com"}, { "_id": 2, "name": "Google", "url": "https://www.google.com"} ] x = mycol.insert_many(mylist) print(x.inserted_ids)
删除:
# 删除单条 myquery = { "name": "百度" } mycol.delete_one(myquery) # 删除多条(删除http协议网站) myquery = { "url": {"$regex": "^http:"} } x = mycol.delete_many(myquery) print("已删除文档个数:", x.deleted_count) # 删除所有文档 x = mycol.delete_many({}) # 删除集合 mycol.drop()
修改:
# 修改单条 myquery = { "id": "1" } newvalues = { "$set": { "name": "No 1" } } mycol.update_one(myquery, newvalues) # 修改多条 myquery = { "url": {"$regex": "^http:"} } newvalues = { "$set": { "name": "非HTTPS协议网站" } } x = mycol.update_many(myquery, newvalues) print("已更新文档个数:", x.modified_count)
查询:
# 查询文档第一条数据 x = mycol.find_one() # 查询文档所有数据 for x in mycol.find(): print(x) # 查询指定字段(指定1,表示需要返回的字段),注意,除_id外,其他字段不能0或1必须一致 for x in mycol.find({},{ "_id": 0, "name": 1, "url": 1 }): print(x) # 反向返回字段(返回除url之外的其他字段) for x in mycol.find({},{ "url": 0 }): print(x) # 根据条件查询 myquery = { "name": "Chinmoku" } mydoc = mycol.find(myquery) for x in mydoc: print(x) # 使用修饰符查询(比较name首字母) myquery = { "name": { "$gt": "H" } } mydoc = mycol.find(myquery) for x in mydoc: print(x) # 正则查询(查询name以C开头的数据) myquery = { "name": { "$regex": "^C" } } mydoc = mycol.find(myquery) for x in mydoc: print(x) # 返回指定条数 myresult = mycol.find().limit(3) for x in myresult: print(x)
参考
著作権声明
本記事のリンク:https://www.chinmoku.cc/dev/java/database/mongodb-tutorial/
本博客中的所有内容,包括但不限于文字、图片、音频、视频、图表和其他可视化材料,均受版权法保护。未经本博客所有者书面授权许可,禁止在任何媒体、网站、社交平台或其他渠道上复制、传播、修改、发布、展示或以任何其他方式使用此博客中的任何内容。