当前位置 : 首页 » 文章分类 :  开发  »  MongoDB

MongoDB

MongoDB 使用笔记


简介

MongoDB 是 C++ 编写的一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为 Web 应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。
MongoDB 文档类似于 Json 对象。字段值可以包含其他文档,数组及文档数组。

MongoDB与Redis比较

MongoDB 文件存储是 Bson 格式,类似 Json, 或自定义的二进制格式。MongoDB 与 Redis性能都很依赖内存的大小,MongoDB有丰富的数据表达、索引;最类似于关系数据库,支持丰富的查询语言,Redis数据丰富,较少的 IO,这方面MongoDB优势明显。
MongoDB 不支持事务,靠客户端自身保证,Redis 支持事务,比较弱,仅能保证事务中的操作按顺序执行,这方面Redis优于MongoDB。
MongoDB 对海量数据的访问效率提升,Redis 较小数据量的性能及运算,这方面MongoDB优于Redis。
MongoDB 有 MapReduce 功能,提供数据分析,Redis没有,这方面MongoDB优于Redis。

MongoDB与关系数据库术语对比

mongodb与关系型数据库的对比

关系数据库概念 MongoDB概念 说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins 表连接,MongoDB不支持(嵌套文档)
primary key primary key 主键,MongoDB自动将_id字段设置为主键
aggregate(group) aggregate(pipeline mapReduce) 聚合

场景

适用场景

1)实时的CRU操作,例如网站、论坛的实时数据处理。它非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
2)缓存。由于性能很高,它适合作为信息基础设施的缓存层。在系统重启之后,由它搭建的持久化缓存层可以避免下层的数据源过载。
3)高伸缩性的场景,分布式集群动态增删节点。非常适合由数十或数百台服务器组成的数据库,内部包含对 MapReduce 引擎的内置支持。
4)用于对象及 JSON 数据的存储:Mongo 的 BSON 数据格式非常适合文档化格式的存储及查询

不适用场景

1)高度事务性操作,如银行或会计系统。
2)传统商业智能(BI)应用,如提供高度优化的查询方式。
3)复杂的跨文档(表)级联查询。

选型决策

列出应用特征的 Yes/No 选项

1、应用不需要事务及复杂 join 支持必须 Yes

2、新应用,需求会变,数据模型无法确定,想快速迭代开发?
3、应用需要2000-3000以上的读写QPS(更高也可以)?
4、应用需要TB甚至 PB 级别数据存储?
5、应用发展迅速,需要能快速水平扩展?
6、应用要求存储的数据不丢失?
7、应用需要99.999%高可用?
8、应用需要大量的地理位置查询、文本查询?

如果上述有1个 Yes,可以考虑 MongoDB,2个及以上的 Yes,选择MongoDB绝不会后悔

场景举例

游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新
物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能
物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析
视频直播,使用 MongoDB 存储用户信息、礼物信息等


Mongo数据类型

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 正则表达式类型。用于存储正则表达式。


磁盘空间

drop db 会立即释放磁盘空间。
drop collection 不会立即释放空间,但被删除的collection占用的空间可以被复用。


内存

MongoDB如何使用内存

目前,MongoDB使用的是内存映射存储引擎,它会把磁盘IO操作转换成内存操作,如果是读操作,内存中的数据起到缓存的作用,如果是写操作,内存还可以把随机的写操作转换成顺序的写操作,总之可以大幅度提升性能。MongoDB并不干涉内存管理工作,而是把这些工作留给操作系统的虚拟缓存管理器去处理,这样的好处是简化了MongoDB的工作,但坏处是你没有方法很方便的控制MongoDB占多大内存,事实上MongoDB会占用所有能用的内存,所以最好不要把别的服务和MongoDB放一起。

如何强行收回内存

1、重启mongodb,或者调用 db.runCommand({closeAllDatabases:1}) 来清除内存
2、使用Linux命令清除缓存中的数据:echo 3 > /proc/sys/vm/drop_caches

wiredTigerCacheSizeGB

mongod 提供了额外的可选参数 wiredTigerCacheSizeGB 来控制 WiredTiger 存储引擎所占用的 cache size
例如

wiredTigerCacheSizeGB=10

注意:
1、若不设置 wiredTigerCacheSizeGB 大小,mongodb 服务会根据本机内存设置内存大小
2、cache size设置较低,同时mongodb复杂查询很频繁的话,会有延迟发生。


索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB 在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

db.col.getIndexes() 查看索引

> db.msg_send.getIndexes();
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_"
    },
    {
        "v" : 2,
        "key" : {
            "expireAt" : 1
        },
        "name" : "expireAt",
        "expireAfterSeconds" : NumberLong(0)
    }
]

db.col.totalIndexSize() 查看索引大小

db.col.dropIndexes() 删除所有索引

db.col.dropIndex(“idx_name”) 删除指定索引

db.col.createIndex() 创建索引

MongoDB 使用 createIndex() 方法来创建索引。
注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex(), 之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名。

db.collection.createIndex(keys, options)
keys 指定一个或多个索引字段,例如 {"name":1}, {"name":1, "age":-1}, 1是升序,-1是降序
options 选项指定索引特性
例如在后台创建索引 db.collection.createIndex({"name":1}, {background: true})

background Boolean 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 “background” 可选参数。 默认值为false。
unique Boolean 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name string 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDups Boolean 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparse Boolean 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSeconds integer 指定一个以秒为单位的数值,完成 TTL 设定,设定集合的生存时间。
v index version 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weights document 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_language string 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_override string 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

TTL索引设置数据生存时间

TTL 索引是一种特殊索引,通过这种索引 MongoDB 会过一段时间后自动移除集合中的文档。
可以设置在指定的时间段后或在指定的时间点过期,MongoDB 有独立线程去清除数据,类似于设置定时自动删除任务。

TTL 索引不能保证过期数据会被立刻删除。在文档过期和 MongoDB 从数据库中删除文档之间,可能会有延迟。
删除过期数据的后台任务每隔 60 秒运行一次。所以,在文档过期之后和后台任务运行结束之前,文档会依然存在于集合中。

Timing of the Delete Operation
https://docs.mongodb.com/manual/core/index-ttl/#timing-of-the-delete-operation

通过 db.collection.createIndex() 命令配合 expireAfterSeconds 选项来对集合中某个字段做 TTL 索引。
这个字段必须是 Date 类型或者是一个包含 Date 类型值的数组字段
如果这个键是一个数组,那么当其中最早过期的时间得到匹配时,这篇文档就会过期失效了。

指定一段时间后过期

例如设置以下数据在 3600 秒之后过期

{
    "_id": "5f43d5c00b34962beb026aad",
    "createdAt": Date(),
    "requestTime": 1598281152423,
    "logId": "1598281152423-6245975993217447",
}

createdAt 字段是插入时间,在其上创建正序索引,指定 expireAfterSeconds 3600 秒之后过期,含义是:在 createdAt 字段的值的时刻基础上,再加上 3600 秒之后的那个时间点过期。
db.logs.createIndex({ "createdAt": 1 }, {expireAfterSeconds: 3600 })

指定过期时间点

有时为了避开访问高峰期,希望在凌晨某个时间点过期,此时可以在文档中加入一个指定过期时间点的字段,然后将 expireAfterSeconds 设为 0
例如

{
    "_id": "5f43d5c00b34962beb026aad",
    "createdAt": Date(),
    "expireAt": ISODate("2020-09-02T11:44:11.528Z"),
    "logId": "1598281152423-6245975993217447",
}

然后在 expireAt 字段创建正序索引,指定 expireAfterSeconds 为 0, 所以 Mongo 会在 expireAt 的时间点加上 0 秒后的时间点删除数据。
db.logs.createIndex({ "expireAt": 1 }, {"expireAfterSeconds": 0})


mongostat

mongostat 是 mongodb 自带的状态检测工具,在命令行下使用,会间隔固定时间(默认1s)获取 mongodb 的当前运行状态,并输出。


Mongo复制集

Mongodb 副本集是一种典型的高可用部署模式,副本集是一组服务器,一般是一个主节点(Primary)用来处理客户端的读写请求,多个副本节点(Secondary)节点对主节点的数据进行备份,以防止主节点宕机导致的单点故障。一旦主节点宕机后,那么整个副本集会进行一次新的选举,选举出一个新的节点成为主服务器。这种副本集部署模式,在主节点挂掉后,仍然可以从副本节点进行读取数据。保证业务的可用性。

MongoDB 的副本集协议(内部称为pv1),是一种 raft-like 协议,即基于 raft 协议的理论思想实现,并且对之进行了一些扩展。

心跳检测

一旦一个副本集创建成功,那么每一个节点之间都保持着通信,每 2s 会向整个副本集的其他节点发一次心跳通知,也就是一个 pings 包。在任意一个节点的数据库内部,维护着整个副本集节点的状态信息,一旦某一个节点超过10s不能收到回应,就认为这个节点不能访问。

另外,对于主节点而言,除了维护这个状态信息外,还要判断是否和大多数节点可以正常通信,如果不能,则要主动降级。

选举的前提条件,参与选举的节点必须大于等于 N/2 + 1 个节点,如果正常节点数已经小于一半,则整个副本集的节点都只能为只读状态,整个副本集将不能支持写入。也不能够进行选举。

成员角色

Primary

Secondary

正常情况下,复制集的 Seconary 会参与 Primary 选举(自身也可能会被选为 Primary),并从 Primary 同步最新写入的数据,以保证与 Primary 存储相同的数据。

Secondary 可以提供读服务,增加 Secondary 节点可以提供复制集的读服务能力,同时提升复制集的可用性。另外,Mongodb 支持对复制集的 Secondary 节点进行灵活的配置,以适应多种场景的需求。

Arbiter

Arbiter 节点只参与投票,不能被选为 Primary,并且不从 Primary 同步数据。

比如你部署了一个2个节点的复制集,1个Primary,1个Secondary,任意节点宕机,复制集将不能提供服务了(无法选出Primary),这时可以给复制集添加一个Arbiter节点,即使有节点宕机,仍能选出Primary。

Arbiter 本身不存储数据,是非常轻量级的服务,当复制集成员为偶数时,最好加入一个 Arbiter 节点,以提升复制集可用性。

Priority0

Priority0 节点的选举优先级为0,不会被选举为 Primary

比如你跨机房A、B部署了一个复制集,并且想指定 Primary 必须在A机房,这时可以将B机房的复制集成员Priority设置为0,这样 Primary 就一定会是A机房的成员。

(注意:如果这样部署,最好将『大多数』节点部署在A机房,否则网络分区时可能无法选出Primary)

Vote0

Mongodb 3.0 里,复制集成员最多50个,参与Primary选举投票的成员最多7个,其他成员(Vote0)的vote属性必须设置为0,即不参与投票。

Hidden 隐藏节点

Hidden 节点不能被选为主(Priority 为 0),并且对 Driver 不可见。因Hidden节点不会接受Driver的请求,可使用Hidden节点做一些数据备份、离线计算的任务,不会影响复制集的服务。

客户端将不会把读请求分发到隐藏节点上,即使我们设定了 复制集读选项 。

这些隐藏节点将不会收到来自应用程序的请求。我们可以将隐藏节点专用于报表节点或是备份节点。 延时节点也应该是一个隐藏节点。

Delayed 延迟节点

Delayed 节点必须是 Hidden 节点,并且其数据落后与Primary一段时间(可配置,比如1个小时)。

因 Delayed 节点的数据比 Primary 落后一段时间,当错误或者无效的数据写入 Primary 时,可通过 Delayed 节点的数据来恢复到之前的时间点。


Primary选举

复制集通过 replSetInitiate 命令(或 mongo shell 的 rs.initiate() )进行初始化,初始化后各个成员间开始发送心跳消息,并发起 Priamry 选举操作,获得『大多数』成员投票支持的节点,会成为 Primary, 其余节点成为 Secondary。

大多数
假设复制集内投票成员(后续介绍)数量为 N, 则大多数为 N/2 + 1, 当复制集内存活成员数量不足大多数时,整个复制集将无法选举出 Primary, 复制集将无法提供写服务,处于只读状态。

通常建议将复制集成员数量设置为奇数。


Mongo Sharding Cluster 分片集群

MongoDB 分片集群技术
https://www.cnblogs.com/clsn/p/8214345.html

分⽚(sharding) 是 MongoDB ⽤来将⼤型集合分割到不同服务器(或者说⼀个集群)上所采⽤的⽅法。

Sharding Cluster 使得集合的数据可以分散到多个 Shard(复制集或者单个 Mongod 节点)存储,使得 MongoDB 具备了横向扩展(Scale out)的能力

分片集群架构

Sharding cluster 由 Shard, Mongos 和 Config server 3 个组件构成:

  • mongos 是一个数据路由进程,是 Sharded cluster 的访问入口,客户端应直接连接 mongos 读写数据。 Mongos 本身并不持久化数据,Sharded cluster 所有的元数据都会存储到 Config Server,而用户的数据则会分散存储到各个shard。Mongos 启动后,会从config server加载元数据,开始提供服务,将用户的请求正确路由到对应的Shard。
  • Config Server 存储集群的所有元数据。包括所有shard节点的信息,分⽚功能的⼀些配置信息等。
  • shard 存储真正的数据,以 chunk 为单位存数据。

Mongo分片集群架构

mongos

mongos 根据 config server 中的分片元数据信息,将客户端发来的请求准确无误的路由到集群中的一个或一组 shard 上,同时会把接收到的响应拼装起来发回到客户端。

当数据写入时,Mongos 根据分片键设计写入数据。

当外部语句发起数据查询时,MongoDB 根据数据分布自动路由至指定节点返回数据。

Mongos 是 MongoDB 分片集群的访问入口,Mongos 收到 Client 访问请求,会根据从 Config Server 获取的路由表将请求转发到后端对应的 Shard 上。

分片集群Mongos到Shard请求管理
https://mongoing.com/archives/3983

Config Server

存储集群所有节点、分片数据路由信息。默认需要配置 3 个 Config Server 节点。

shard


分片策略

Sharded cluster 支持将单个集合的数据分散存储在多个 shard 上,用户可以指定根据集合内文档的某个字段即 shard key 来分布数据,目前主要支持 2 种数据分布的策略:

  • 范围分片(Range based sharding)
  • hash分片(Hash based sharding)

片键shard key

MongoDB 中数据的分片是以集合为基本单位的,集合中的数据通过片键(Shard key)被分成多部分。其实片键就是在集合中选一个键,用该键的值作为数据拆分的依据。

对集合进行分片时,你需要选择一个片键,片键是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB 按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。

分片键是不可变。
分片键必须有索引。
分片键大小限制512bytes。
分片键用于路由查询。
MongoDB不接受已进行collection级分片的collection上插入无分片键的文档(也不支持空值插入)

范围分片(range)


范围分片

对于基于范围的分片,MongoDB 按照片键的范围把数据分成不同部分。

假设有一个数字的片键:想象一个从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点。MongoDB 把这条直线划分为更短的不重叠的片段,并称之为数据块,每个数据块包含了片键在一定范围内的数据。在使用片键做范围划分的系统中,拥有”相近”片键的文档很可能存储在同一个数据块中,因此也会存储在同一个分片中。

优势:范围查询性能好,
劣势:数据分布不均,有热点。

哈希分片(hash)


哈希分片

对于基于哈希的分片,MongoDB 计算一个字段的哈希值,并用这个哈希值来创建数据块。在使用基于哈希分片的系统中,拥有”相近”片键的文档很可能不会存储在同一个数据块中,因此数据的分离性更好一些。

优势:数据分布均匀
劣势:范围查询效率低


chunk

在一个 shard server 内部,MongoDB 还是会把数据分为 chunks, 每个 chunk 代表这个 shard server 内部一部分数据。

Splitting 当一个 chunk 的大小超过配置中的 chunk size 时,MongoDB 的后台进程会把这个 chunk 切分成更小的 chunk,从而避免 chunk 过大的情况

Balancing 在 MongoDB 中,balancer 是一个后台进程,负责 chunk 的迁移,从而均衡各个 shard server 的负载,系统初始 1 个 chunk,chunk size 默认值 64M, 生产库上选择适合业务的 chunk size是最好的,如果单位时间内的存储需求很大,设置更大的 chunk。MongoDB 会自动拆分和迁移 chunks。

chunk size选择

MongoDB 默认的 chunkSize 为 64MB,如无特殊需求,建议保持默认值;chunkSize 会直接影响到 chunk 分裂、迁移的行为。

chunkSize 越小,chunk 分裂及迁移越多,数据分布越均衡;反之,chunkSize 越大,chunk 分裂及迁移会更少,但可能导致数据分布不均。

chunkSize 太小,容易出现 jumbo chunk(即 shardKey 的某个取值出现频率很高,这些文档只能放到一个 chunk 里,无法再分裂)而无法迁移;
chunkSize 越大,则可能出现 chunk 内文档数太多(chunk 内文档数不能超过 250000 )而无法迁移。

chunk 自动分裂只会在数据写入时触发,所以如果将 chunkSize 改小,系统需要一定的时间来将 chunk 分裂到指定的大小。

chunk 只会分裂,不会合并,所以即使将 chunkSize 改大,现有的 chunk 数量不会减少,但 chunk 大小会随着写入不断增长,直到达到目标大小。

chunk 的分裂和迁移非常消耗 IO 资源;
chunk 分裂的时机:在插入和更新,读数据不会分裂。

chunksize的选择:

  • 小的 chunksize:数据均衡是迁移速度快,数据分布更均匀。数据分裂频繁,路由节点消耗更多资源。
  • 大的chunksize:数据分裂少。数据块移动集中消耗IO资源。通常100-200M

chunk分裂与迁移

随着 chunk 中数据的增长,chunk 的大小超过了配置的 chunk size(默认是64M),则这个 chunk 就会分裂成两个。数据的增长会让 chunk 分裂得越来越多。


chunk分裂

这时候,各个 shard 上 chunk 的数量就会不平衡。此时,mongos 中的一个组件 balancer 就会执行自动平衡。把 chunk 从数量最多的 shard 节点挪动到数量最少的节点。


chunk迁移

mongos


Intel/M1 Mac Brew 安装 MongoDB Community

MongoDB 已经宣布不再开源,从2019年9月2日开始 HomeBrew 也从核心仓库当中移除了 mongodb 模块

MongoDB 官方提供了一个单独的 HomeBrew 的社区版本安装 Tap
https://github.com/mongodb/homebrew-brew

1、brew tap 安装 mongodb/brew
brew tap mongodb/brew

2、安装最新 mongodb 社区版 brew install mongodb-community
或者指定版本安装 brew install mongodb-community@4.4

Intel Mac 安装目录 /usr/local/Cellar/mongodb-community/4.4.5
M1 Mac 安装目录 /opt/homebrew/Cellar/mongodb-community/5.0.6

使用 brew services 启动并添加开机启动:
brew services start mongodb-community

前台启动
Intel 版 Mongo mongod --config /usr/local/etc/mongod.conf
M1 版 Mongo mongod --config /opt/homebrew/etc/mongod.conf


启动/停止mongodb

启动MongoDB

1、启动
mongod –dbpath /home/user1/mongodb/data –logpath /home/user1/mongodb/log/logs –fork
mongo服务启动必须要指定文件存放的目录dbpath,–fork以守护进程运行,如果带—fork参数则必须要指定—logpath即日志存放的位置

2、指定配置文件启动
mongod -f conf/mongo_conf.conf

mongod 和 mongo 的区别
mongod 是 MongoDB 的服务端后台进程,mongo 是客户端。

停止MongoDB

1、查看进程并 kill
ps aux|grep mongod
kill -9 pid

2、在客户端中使用 shutdown 命令

> use admin
switched to db admin
> db.auth('admin','123456')
> db.shutdownServer()

MongoDB开启认证

Mongodb 支持 SCRAM 认证,该认证通过用户名、密码认证,基于用户角色进行访问控制,添加账号步骤如下。

创建管理员账户

1、以无访问认证方式启动 mongodb,未开启认证环境下,登录 mongo

mongo localhost:27017

2、查看 mongo 版本:

> db.version();
3.2.16

3、查看数据库:

> show dbs;
local      0.000GB
mytest-db  0.459GB

4、切换到 admin 数据库(注意现在还没有 admin 数据库)
3.0 版本后没有 admin 数据库,但我们可以手动 use 一个。注:use 命令在切换数据库时,如果切换到一个不存在的数据库,MongodDB 会自动创建该数据库
其实 use 后 show dbs 也无法立即看到 admin 数据库,重新登录或者真正有数据插入时才会创建 admin 库

5、创建管理员账户
配置访问控制的第一步是创建用户管理员账户。用户管理员应只有创建用户账户的权限,而不能管理数据库或执行其他管理任务。这确保数据库管理和用户账户管理之间有清晰的界限。
如果 mongo 版本是 3.0 以前,则用 db.addUser 创建用户

db.createUser({
        user: "adminuser",
        pwd: "adminpd",
        roles: [{role: "userAdminAnyDatabase", db: "admin"}]
});

Successfully added user: {
    "user" : "adminuser",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ]
}

角色说明: userAdminAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的 userAdmin 权限

创建普通账户

1、切换到 mytest-db 数据库

> use mytest-db;
switched to db mytest-db

2、创建普通账户

db.createUser({
      user:"dbuser",
      pwd: "dbuserpd",
      roles: [{ role: "readWrite", db: "mytest-db"}]
});

Successfully added user: {
    "user" : "dbuser",
    "roles" : [
        {
            "role" : "readWrite",
            "db" : "mytest-db"
        }
    ]
}

重启Mongo开启认证

1、编辑 mongo 配置文件,开启认证
编辑 mongodb-3.2.16/conf/mongo_conf.conf 将 auth 设为 true

port=27017
dbpath=/data1/mongo_data/
logpath=logs/mongo.log
pidfilepath=pid/config.pid
fork=true
logappend=true
auth=true

2、重新启动 mongo,开启认证

# ./bin/mongod -f conf/mongo_conf.conf
about to fork child process, waiting until server is ready for connections.
forked process: 1474
child process started successfully, parent exiting

登录Mongo后通过 db.auth() 认证

1、重新登录 mongo
mongo localhost:27019
登录后,如果不先认证,执行命令会报错:

> show dbs;
2021-12-01T17:38:59.195+0800 E QUERY    [thread1] Error: listDatabases failed:{
    "ok" : 0,
    "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
    "code" : 13
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:769:19
shellHelper@src/mongo/shell/utils.js:659:15
@(shellhelp2):1:1

切换到对应数据库后,用 db.auth('用户名', '密码') 认证即可:

> use admin;
switched to db admin
> db.auth('adminuser','adminpd')
1
> show dbs;
admin      0.000GB
local      0.000GB
mytest-db  0.459GB

> use mytest-db;
switched to db mytest-db
> db.auth('dbuser','dbuserpd')
1
> show collections;
fs.chunks
fs.files

带认证信息登录mongo

或者可以直接登录填入账号密码
mongo localhost:27019 -u adminuser -p adminpd –authenticationDatabase admin
mongo localhost:27019 -u dbuser -p dbuserpd –authenticationDatabase mytest-db


未开启认证的mongo带密码无法登录

未开启认证的 mongo 带密码无法登录,所以服务连接带上认证参数后,就不能连接无密码的 mongo 了。

# mongo localhost:27019 -u dbuser -p dbuserpd --authenticationDatabase admin
MongoDB shell version v3.6.14
connecting to: mongodb://localhost:8017/test?authSource=admin&gssapiServiceName=mongodb
2022-03-16T13:30:02.938+0000 E QUERY    [thread1] Error: Authentication failed. :
connect@src/mongo/shell/mongo.js:263:13
@(connect):1:6
exception: connect failed

Mongo Profiler 慢查询记录

Database Profiler
https://www.mongodb.com/docs/manual/tutorial/manage-the-database-profiler/

开启 Profiler 记录

Profiling 级别:

  • 0 关闭,不收集任何数据。
  • 1 收集慢查询数据,默认记录超 100 毫秒的操作。
  • 2 收集所有数据

1、修改 mongo.conf 配置文件开启 Mongo Profiler 记录

#开启慢查询,200毫秒的记录
profile = 1
slowms = 200

2、通过命令开启(重启后失效)
db.getProfilingStatus() 查看 Profiling 状态,was 是级别,slowms 是慢查询阈值,默认是 0 级 100 毫秒
db.setProfilingLevel(1,1000); 设置级别和慢查询时间,经测试好像 Profiler 级别是各个 DB 独立的,但 slowms 时间阈值是各个 DB 共享的

mongodb-shard-0:PRIMARY> db.getProfilingStatus();
{
    "was" : 0,
    "slowms" : 100,
    "sampleRate" : 1,
    "$gleStats" : {
        "lastOpTime" : Timestamp(0, 0),
        "electionId" : ObjectId("7fffffff0000000000000003")
    },
    "lastCommittedOpTime" : Timestamp(1651718015, 1),
    "$configServerState" : {
        "opTime" : {
            "ts" : Timestamp(1651718009, 2),
            "t" : NumberLong(1017)
        }
    },
    "$clusterTime" : {
        "clusterTime" : Timestamp(1651718015, 1),
        "signature" : {
            "hash" : BinData(0,"ACzOHeOEXiTez+Mpo/bQp7q6rx8="),
            "keyId" : NumberLong("7075910314662821911")
        }
    },
    "operationTime" : Timestamp(1651718015, 1)
}

mongodb-shard-0:PRIMARY> db.setProfilingLevel(1,1000);
{
    "was" : 0,
    "slowms" : 100,
    "sampleRate" : 1,
    "ok" : 1,
    "$gleStats" : {
        "lastOpTime" : Timestamp(0, 0),
        "electionId" : ObjectId("7fffffff0000000000000003")
    },
    "lastCommittedOpTime" : Timestamp(1651718025, 1),
    "$configServerState" : {
        "opTime" : {
            "ts" : Timestamp(1651718016, 2),
            "t" : NumberLong(1017)
        }
    },
    "$clusterTime" : {
        "clusterTime" : Timestamp(1651718025, 1),
        "signature" : {
            "hash" : BinData(0,"4n6mFR5/lZKTb81r5hvbEwP7R0s="),
            "keyId" : NumberLong("7075910314662821911")
        }
    },
    "operationTime" : Timestamp(1651718025, 1)
}

关闭 Profiler 记录:
db.setProfilingLevel(0)

查看慢查询日志

查询全部慢日志 db.system.profile.find().pretty();
或查询耗时 ts 最大的 10 条记录 db.system.profile.find().limit(10).sort( { ts : -1 } ).pretty()


mongo连接

mongo 连接本地27017端口

mongo 连接本机 27017 端口的 mongo 等于 mongo localhost:27017mongo 127.0.0.1:27017

mongo –host host –port port 连接指定host上的mongo

如果忽略 --host 默认连接 127.0.0.1, 如果忽略 --port 默认连接 27017
mongo --host host 连接指定 host 上 27017 端口的 mongo
mongo --port 27017 连接本地 27017 端口的 mongo

mongo host:port 连接指定host端口

mongo 192.168.1.100:27017 指定 host 和端口连接 mongo

# mongo localhost:27019
MongoDB shell version: 3.2.16
connecting to: localhost:27019/test

mongo host:port/db 指定host端口数据库连接

mongo 192.168.1.100:27017/test 指定host、端口、数据库名连接

mongo host:port/db -u u -p p 指定账号密码连接

mongo 192.168.1.200:27017/test -u user -p password 指定host、端口、用户名、密码、数据库名连接


Mongo查看版本号

mongo –version(未连接时)

未登录 mongo 时 mongo --versionmongod --version

mongo --version
MongoDB shell version v4.4.0
Build Info: {
    "version": "4.4.0",
    "gitVersion": "563487e100c4215e2dce98d0af2a6a5a2d67c5cf",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}

db.version() 已连接时

已登录 mongo 后:

> db.version();
4.4.0

Database Methods 数据库命令

https://docs.mongodb.com/manual/reference/method/js-database/

查看所有账号信息

>  use admin
switched to db admin
> db.auth('admin','123456')
1
> db.system.users.find().pretty()

db.adminCommand() 执行admin数据库命令

https://docs.mongodb.com/manual/reference/method/db.adminCommand/#mongodb-method-db.adminCommand


迁移collection

db1 中的 test1 改名为 test2
db.adminCommand({renameCollection: “db1.test1”, to: “db1.test2”})

还可以跨 db 迁移 collection, 比如将 db1.test1 迁移到 db2.test2
db.adminCommand({renameCollection: “db1.test1”, to: “db2.test2”})
此时会将 db1.test1 的数据拷贝到 db2.test2, 如果 db2 中已有 test2 集合会将其 drop 掉。

renameCollection
https://docs.mongodb.com/manual/reference/command/renameCollection/

show dbs 查看数据库

show dbsshow databases 查看数据库

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

db 查看当前数据库

use db 切换/创建数据库

mongo 中创建数据库采用的也是 use 命令,如果 use 后面跟的数据库名不存在,那么 mongo 将会新建该数据库。
不过,实际上只执行 use 命令后,mongo 是不会新建该数据库的,直到你像该数据库中插入了数据。

db.dropDatabase() 删除db

> db.dropDatabase()
{ "dropped" : "test", "ok" : 1 }

show collections 查看当前库中的集合

db.createCollection(name, options) 创建集合

name: 要创建的集合名称
options: 可选参数, 指定有关内存大小及索引的选项

capped 布尔(可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。
autoIndexId 布尔 3.2 之后不再支持该参数。(可选)如为 true,自动在 _id 字段创建索引。默认为 false。
size 数值 (可选)为固定集合指定一个最大值,即字节数。如果 capped 为 true,也需要指定该字段。
max 数值(可选)指定固定集合中包含文档的最大数量。

注意:MongoDB 中不需要单独创建集合。当插入文档到某个集合时,MongoDB 会自动创建不存在的集合


db.currentOp() 查看正在执行的连接

https://www.mongodb.com/docs/manual/reference/method/db.currentOp/

查看当前正在进行的 mongo 操作,类似 MySQL 的 show processlist

secs_running 操作持续时间(秒),等于当前时间减去操作开始时间
microsecs_running 操作持续时间(微秒)
active 操作是否开启,空连接或内部空闲线程是非活跃的
op 操作类型,比如 insert, update, query, remove
ns 操作的db和collection名,格式 <database>.<collection>

查询执行时间超过1秒的慢查询操作

db.currentOp({ "secs_running": { "$gt": 1 }, "active": true })


Collection Methods 集合命令

Collection Methods
https://docs.mongodb.com/manual/reference/method/js-collection/

db.col.drop() 删除集合

db.col.renameCollection() 集合重命名

修改 msg 集合名为 msg_bak_531

> db.msg.renameCollection("msg_bak_531");
{ "ok" : 1 }

db.col.insert() 插入文档

如果集合 col 在该数据库中不存在, MongoDB 会自动创建该集合并插入文档。

db.col.save() 插入或更新文档

save() 如果 _id 主键存在则更新数据,如果不存在就插入数据。
该方法新版本中已废弃,可以使用 db.collection.insertOne()db.collection.replaceOne() 来代替。

db.col.insertMany() 批量插入数据


db.col.find() 文档查询

> db.col.find();
{ "_id" : ObjectId("605852c8268f6ff446491871"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }
{ "_id" : ObjectId("6058672a268f6ff446491872"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }

条件查询

查询 success 是 false 的文档
db.col.find({"success":false});

json嵌套查询

查询 msg 表中 code=code37,content.userName等于 xiaoming 的数据

db.msg.find({
    "code": "code37",
    "content.userName": {
        $eq:"xiaoming"
        }
    }).limit(1);

sort() 排序

1 升序,-1 降序

查询时间倒序排序第一个成功的:
db.col.find({“success”:true}).sort({“createdDate”:-1}).limit(1);

limit() 指定返回结果数

> db.col.find().limit(2);

skip() 指定偏移量


count() 计数

count 计数
db.col.find({"success":false}).count();

count("a":null) 查询字段为空或不存在的文档
> db.col.find({"type":null}).limit(2);

db.col.count() 查看集合中的文档数

count 计数
db.col.count({"success":false});


db.col.deleteMany() 条件删除

删除 type 字段为 null 或不存在的文档

> db.col.deleteMany({"type":null});
{ "acknowledged" : true, "deletedCount" : 6896 }

db.col.remove() 条件删除

删除 success 是 false 的文档
db.col.remove({"success": false});


db.col.aggregate() 聚合查询

db.collection.aggregate()
https://docs.mongodb.com/manual/reference/method/db.collection.aggregate/

文档重复查询及删除

查询 msgcode 重复的文档

db.col.aggregate([
    { $group: { _id : '$msgCode', count: { $sum : 1 } } },
    { $match: { count: { $gt : 1} } }
])

查询 msgcode 重复的文档并删除

db.col.aggregate([
    { $group: {_id : '$msgCode', count: {$sum : 1}, dups:{$addToSet:'$_id'}}},
    { $match: {count: {$gt:1} } 
    } ]).forEach(function(it) { 
        it.dups.shift(); 
        db.msg_send.remove({_id: {$in: it.dups}});
    });

解释:
$group 中是聚合条件,根据 msgCode 字段聚合。
count 统计重复出现的次数, $match 过滤出现重复的数据
$addToSet 将聚合的数据id放入到 dups 数组中方便后面使用
forEach 对查询结果进行遍历
shift() 作用是剔除队列中第一条id,避免删掉所有的数据

删除重复msgcode
https://segmentfault.com/a/1190000020056997


Replication Methods 复制集命令

https://docs.mongodb.com/manual/reference/method/js-replication/

rs.status() 查看复制集状态

https://docs.mongodb.com/manual/reference/method/rs.status/#mongodb-method-rs.status

> rs.status();
{
    "ok" : 0,
    "errmsg" : "not running with --replSet",
    "code" : 76,
    "codeName" : "NoReplicationEnabled"
}

Sharding Methods 分片命令

https://docs.mongodb.com/manual/reference/method/js-sharding/

sh.status() 查看分片集群状态

https://docs.mongodb.com/manual/reference/method/sh.status/#mongodb-method-sh.status

打印 sharding 配置和 chunks 信息,需要在 mongos 上执行。

在非 mongos 上执行时提示:

> sh.status();
printShardingStatus: this db does not have sharding enabled. be sure you are connecting to a mongos from the shell and not to a mongod.

MongoDB时间少8小时

现象:
通过 Spring Boot Data MongoDB 保存到 mongo 中的时间,在 mongo shell db.col.find(); 查看时少 8 个小时,但 Java 代码中保存日志和查询出来的时间都是正常的。

原因:
MongoDB 自带的 Date 是 UTC/GMT 时间,中国是东八区(UTC+8)。
MongoDB 中的 Date 类型数据只保存绝对时间值,不保存时区信息,因此“显示的时间”取决于 MongoDB 的客户端设置。

解决:
MongoDB 服务端只能以 UTC/GMT 存储时间,不支持时区设置,只能在各个客户端修改时区
如果使用可视化工具 Robomongo 的话,可以通过”Options” - “Display Dates in…” - “Local Timezone” 来设置显示本地时间。


上一篇 typesafe.config与HOCON

下一篇 Apache-Commons-Validator 笔记

阅读
评论
9.7k
阅读预计39分钟
创建日期 2020-08-19
修改日期 2022-05-05
类别
目录
  1. 简介
    1. MongoDB与Redis比较
    2. MongoDB与关系数据库术语对比
    3. 场景
      1. 适用场景
      2. 不适用场景
      3. 选型决策
      4. 场景举例
  2. Mongo数据类型
  3. 磁盘空间
  4. 内存
    1. MongoDB如何使用内存
    2. 如何强行收回内存
    3. wiredTigerCacheSizeGB
  5. 索引
    1. db.col.getIndexes() 查看索引
    2. db.col.totalIndexSize() 查看索引大小
    3. db.col.dropIndexes() 删除所有索引
    4. db.col.dropIndex(“idx_name”) 删除指定索引
    5. db.col.createIndex() 创建索引
    6. TTL索引设置数据生存时间
      1. 指定一段时间后过期
      2. 指定过期时间点
  6. mongostat
  7. Mongo复制集
    1. 心跳检测
    2. 成员角色
      1. Primary
      2. Secondary
      3. Arbiter
      4. Priority0
      5. Vote0
      6. Hidden 隐藏节点
      7. Delayed 延迟节点
    3. Primary选举
  8. Mongo Sharding Cluster 分片集群
    1. 分片集群架构
      1. mongos
      2. Config Server
      3. shard
    2. 分片策略
      1. 片键shard key
      2. 范围分片(range)
      3. 哈希分片(hash)
    3. chunk
      1. chunk size选择
      2. chunk分裂与迁移
  9. mongos
  10. Intel/M1 Mac Brew 安装 MongoDB Community
  11. 启动/停止mongodb
    1. 启动MongoDB
    2. 停止MongoDB
  12. MongoDB开启认证
    1. 创建管理员账户
    2. 创建普通账户
    3. 重启Mongo开启认证
    4. 登录Mongo后通过 db.auth() 认证
    5. 带认证信息登录mongo
    6. 未开启认证的mongo带密码无法登录
  13. Mongo Profiler 慢查询记录
    1. 开启 Profiler 记录
    2. 查看慢查询日志
  14. mongo连接
    1. mongo 连接本地27017端口
    2. mongo –host host –port port 连接指定host上的mongo
    3. mongo host:port 连接指定host端口
    4. mongo host:port/db 指定host端口数据库连接
    5. mongo host:port/db -u u -p p 指定账号密码连接
  15. Mongo查看版本号
    1. mongo –version(未连接时)
    2. db.version() 已连接时
  16. Database Methods 数据库命令
    1. 查看所有账号信息
    2. db.adminCommand() 执行admin数据库命令
      1. 迁移collection
    3. show dbs 查看数据库
    4. db 查看当前数据库
    5. use db 切换/创建数据库
    6. db.dropDatabase() 删除db
    7. show collections 查看当前库中的集合
    8. db.createCollection(name, options) 创建集合
    9. db.currentOp() 查看正在执行的连接
      1. 查询执行时间超过1秒的慢查询操作
  17. Collection Methods 集合命令
    1. db.col.drop() 删除集合
    2. db.col.renameCollection() 集合重命名
    3. db.col.insert() 插入文档
    4. db.col.save() 插入或更新文档
    5. db.col.insertMany() 批量插入数据
    6. db.col.find() 文档查询
      1. 条件查询
      2. json嵌套查询
      3. sort() 排序
      4. limit() 指定返回结果数
      5. skip() 指定偏移量
      6. count() 计数
    7. db.col.count() 查看集合中的文档数
    8. db.col.deleteMany() 条件删除
    9. db.col.remove() 条件删除
    10. db.col.aggregate() 聚合查询
      1. 文档重复查询及删除
  18. Replication Methods 复制集命令
    1. rs.status() 查看复制集状态
  19. Sharding Methods 分片命令
    1. sh.status() 查看分片集群状态
  20. MongoDB时间少8小时

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论