mongodb笔记

安装指南 MongoDB Command Reference MongoDB Manual

性能优化

  • 文档扫描量大,没有建立索引
  • 查询返回的文档空间过大,使用查询选择踢除不必要的字段
  • 限制单次查询的返回数量
  • 大数据记录,使用投影选项,只返回必要的字段
  • 数据库性能只有在使用所有使用的索引都加载到内存里才是最好的。需要 db.stats()db.collection.stats 输出的信息来帮助计划需要多少磁盘空间和 RAM 才能运行 MongoDB。应该为预期的数据留足够的磁盘空间,包括一些安全空间和热数据(工作数据集合)
  • 不合理的索引顺序令查询效率收效甚微
    索引元数据 `keys = {a:1, b:1, c:1}
    db.xxx.find({a:xx})` 能利用索引
    db.xxx.find({b:xx})` 不能利用索引
    
  • 不要滥用索引,索引本身是有成本的。大量增删改记录,会刷新索引信息。不要让索引本身对业务查询造成性问题
  • 尝试给经常用在查询条件的字段建立索引,加速查询
  • 自托管 MongoDB 设置 ulimit 规定 ulimit 设置参考

索引

  • 默认主键有索引作用,ObjectId的生成算法,具备索引特性。 | 字节 | 含义 | |—–|——| | 4B | 时间戳(秒级,文档创建时间) | | 5B | 机器+进程随机数(保证不同机器/进程唯一性) | | 3B | 自增计数器(同一秒内的序号) |

  • 复合主键不等于复合索引
    • 复合主键仍然以 _id 的对象整体计算得的值,来主键索引记录。查询时不能缺少复合主键的任何一个字段
    • 而复合索引跟多个索引字段,分批索引。查询时可能缺少其它字段
  • 建立索引
    db.runCommand({
    createIndexes: "<collection-name>",
    indexes: [
      {
        key: { <field1>: <type>, <field2>: <type>, ... },
        name: "<index-name>",
        // 其他选项...
      },
      // 可以添加多个索引
    ]
    })
    
参数 说明
createIndexes 集合名称(字符串),表示要在哪个集合上创建索引
indexes 索引数组,每个对象定义一个索引
key 索引的字段及其排序方式(1 表示升序,-1 表示降序)
name 索引名称(可选,不填则自动生成)
其他选项 如 unique、sparse、expireAfterSeconds 等
选项 说明
unique: true 创建唯一索引,禁止重复值
sparse: true 稀疏索引,只包含有该字段的文档
expireAfterSeconds: N TTL 索引,用于自动删除过期文档(N 是秒数)
background: true 后台创建索引(避免阻塞其他操作)
partialFilterExpression 创建部分索引(只对满足条件的文档建立索引)

副本集

uri连接规则

  • uri尽管填的是从节点地址x.x.x.x:27017,实际上mongodb client,在从节点返回的副本集集群信息中,选择一个主节点连接
    mongodb://admin:123456@x.x.x.x:27017/?authSource=admin
    

    如果需要强制连接从节点,需要增加参数 &readPreference=secondary&directConnection=true

    mongodb://admin:admin123@10.9.0.12:27017/?authSource=admin&readPreference=secondary&directConnection=true
    mongodb://yunying:R7mK9pQx2NvB8wE@192.168.2.152:27017/?authSource=admin&readPreference=secondary&directConnection=true
    

创建副本集

  • 各节点mongod.conf增加集群名称 ``` replication: replSetName: “rs0” # 副本集名称,所有节点必须一致

security: authorization: enabled # 生产环境必须启用认证


- 连接任一节点
mongosh --host 192.168.1.101 --port 27017

// 初始化副本集 rs.initiate({ _id: “rs0”, members: [ { _id: 0, host: “192.168.1.101:27017”, priority: 2 }, { _id: 1, host: “192.168.1.102:27017”, priority: 1 }, { _id: 2, host: “192.168.1.103:27017”, priority: 1 } ] })

// 查看副本集状态
rs.status()

## 重新配置副本集
// 1. 获取当前配置(即使显示旧IP也没关系)
cfg = rs.conf()

// 2. 修改每个成员的 host 为新IP(保持 _id 不变!)
cfg.members[0].host = "192.168.3.66:27017"  // node1 新IP
cfg.members[1].host = "192.168.3.201:27017"  // node2 新IP
cfg.members[2].host = "192.168.3.93:27017"  // node3 新IP

// 3. 可选:调整优先级(确保某节点优先成为 Primary)
cfg.members[0].priority = 2
cfg.members[1].priority = 1
cfg.members[2].priority = 1

// 4. 强制重新配置(因多数节点可能不可达,需加 force)
rs.reconfig(cfg, { force: true })
# 设置用户权限

### 设置只读账号

```javascript
use admin
db.createUser({
  user: "yunying",
  pwd: "R7mK9pQx2NvB8wE",
  roles: [
    { role: "read", db: "xxxxxx" } // 只读权限,仅此库
  ]
})

修改密码

db.changeUserPassword("yunying", "R7mK9pQx2NvB8wE")

备份与恢复

方法一:mongodump & mongorestore

导出所有数据实例,默认对当前运行的 db 实例导出、导入的对象操作。

# 导出
mongodump -h <ADDR> -d <DB_NAME> -o $EXPORT_PATH --gzip
# 导入
mongorestore -h <ADDR> -d <DB_NAME> $IMPORT_PATH --gzip

方法二:mongoexport & mongoimport

mongoexport
mongoimport

两种方式的区别

注意:避免在生产环境中使用 mongoimport 和 mongoexport 进行完整实例备份。它们不能可靠地保留所有 BSON 数据类型,因为 JSON 只能表示 BSON 支持的类型的一个子集。对于此类功能,请使用 MongoDB 备份方法中描述的 mongodump 和 mongorestore。

  • mongodump 导出的是 BSON 格式,是二进制形式,可以使用 mongo 自带的 bsondump 命令查看里面的数据
  • mongoexport 导出的则是文本,可以是 CSV、JSON 格式
  • JSON 可读性强但体积较大,BSON 是二进制文件,体积小但对人类几乎没有可读性
  • 在一些 MongoDB 版本之间,BSON 格式可能会随版本不同而有所不同,所以不同版本之间用 mongodump/mongorestore 可能不会成功,具体要看版本之间的兼容性
  • 当无法使用 BSON 进行跨版本的数据迁移的时候,使用 JSON 格式即 mongoexport/mongoimport 是一个可选项
  • 跨版本的 mongodump/mongorestore 个人并不推荐,实在要做请先检查文档看两个版本是否兼容
  • JSON 虽然具有较好的跨版本通用性,但其只保留了数据部分,不保留索引、账户等其他基础信息。使用时应该注意。

数据库部署&配置

日志轮转

/var/log/mongodb/mongod.log 是 MongoDB 的日志文件,它记录了 MongoDB 数据库服务器运行过程中的各种信息。这个文件在排查问题、优化性能、监控数据库状态等方面非常有用。

  • 如果没有配置 logrotate 或 MongoDB 未启用日志轮转,日志会一直增长,直到占满磁盘
  • 如果开启了 logLevel: 1 或更高(调试级别),会记录大量细节。例如使用了 setLogLevel() 设置了详细日志

配置步骤

  1. 编辑 MongoDB 的配置文件(通常是 /etc/mongod.conf),确保包含以下内容:

    systemLog:
      destination: file
      path: /var/log/mongodb/mongod.log
      logAppend: true
      logRotate: reopen
    
  2. 设置 logrotate 规则:

    sudo nano /etc/logrotate.d/mongodb
    
  3. 添加以下内容:

    /var/log/mongodb/mongod.log {
        daily
        missingok
        rotate 7
        compress
        notifempty
        create 0644 mongod mongod
        postrotate
            systemctl kill -s USR1 mongod
        endscript
    }
    

基本操作

连接数据库

// 连接指定数据库
mongo YOUR_TARGET_DB

// 显示当前连接的数据库
db

// 显示所有数据库
show dbs

// 连接/创建数据库
use YOUR_TARGET_DB

// 删除当前数据库
db.dropDatabase()

// 显示所有集合
show collections

嵌套文档查询

// 使用点号 `.` 访问嵌套字段:
db.YOUR_TARGET_COLLECTION.find({ "FIELD1.FIELD2": "XXXXX" })

//返回第一个匹配的文档
db.YOUR_TARGET_COLLECTION.findOne({ field: value });

// 统计集合中文档总数
db.YOUR_TARGET_COLLECTION.countDocuments()

// 或者使用 count()(已过时,不推荐)
db.YOUR_TARGET_COLLECTION.count()

// 带条件的计数
db.YOUR_TARGET_COLLECTION.countDocuments({ status: "active" })

逻辑表达式

$and

第一个结果为 false 不再执行第二个结果:

{ 
  $and: [
    { startTime: { $lte: 1552713970.0 } }, 
    { endTime: { $gte: 1552713970.0 } } 
  ] 
}

$or

{
  $or: [
    { status: "A" },
    { qty: { $lt: 30 } }
  ]
}

比较操作符

// 等于
db.YOUR_TARGET_COLLECTION.find({ field: value });

// 大于
// field > value
db.YOUR_TARGET_COLLECTION.find({ field: { $gt: value } });

// 小于
// field < value
db.YOUR_TARGET_COLLECTION.find({ field: { $lt: value } });

// 大于等于
// field >= value
db.YOUR_TARGET_COLLECTION.find({ field: { $gte: value } });

// 小于等于
// field <= value
db.YOUR_TARGET_COLLECTION.find({ field: { $lte: value } });

// 不等于
// field != value
db.YOUR_TARGET_COLLECTION.find({ field: { $ne: value } });

// 范围查询
// value1 < field < value2
db.YOUR_TARGET_COLLECTION.find({ field: { $gt: value1, $lt: value2 } });

数组查询

// 匹配数组中的任意一个值
// field IN [v1, v2, v3]
db.YOUR_TARGET_COLLECTION.find({ field: { $in: [v1, v2, v3] } });

// 不匹配数组中的任何值
// field NOT IN [v1, v2, v3]
db.YOUR_TARGET_COLLECTION.find({ field: { $nin: [v1, v2, v3] } });

// 同时包含多个值
// field 包含 v1, v2, v3
db.YOUR_TARGET_COLLECTION.find({ field: { $all: [v1, v2, v3] } });

// 数组长度
// field 数组长度为 3
db.YOUR_TARGET_COLLECTION.find({ field: { $size: 3 } });

// 示例
// 匹配 {name: 'David', age: 26, favorite_number: [6, 7, 9]}
db.users.find({ favorite_number: { $size: 3 } });

取模查询

// field % v1 == v2
db.YOUR_TARGET_COLLECTION.find({ field: { $mod: [v1, v2] } });
  • 取模不能利用索引,需要搭配其它索引字段配合使用

更新文档

update 方法

db.collection.update(
  <query>,
  <update>,
  {
    upsert: <boolean>,
    multi: <boolean>,
    writeConcern: <document>
  }
)

参数说明:

  • query : 更新条件,类似于 SQL 的 WHERE 子句
  • update : 更新操作符和值,类似于 SQL 的 SET 子句
  • upsert : 可选,如果不存在 update 的记录,是否插入新文档,默认为 false
  • multi : 可选,是否更新多条记录,默认为 false(只更新第一条)
  • writeConcern : 可选,抛出异常的级别

更新操作符

$set - 更新或添加字段

注意:如果不使用 $ 操作符,<update> 参数会完全替换匹配的文档,而不是更新特定字段。

// 更新或添加字段
db.collection.update(
  { FIELD: VALUE }, 
  { $set: { field1: "new value" } },
  { multi: true }
);

$unset - 删除字段

// 删除字段
db.collection.update(
  { FIELD: VALUE }, 
  { $unset: { fieldToRemove: 1 } }
);

$inc - 自增/自减

// 自增
db.collection.update(
  { FIELD: VALUE },
  { $inc: { counter: 1 } }  // 增加1
);

// 自减
db.collection.update(
  { FIELD: VALUE },
  { $inc: { counter: -1 } }  // 减少1
);

// 原子操作示例
db.tb_system_param.findAndModify({
  query: { "id": 1 },
  update: { $inc: { "value": 1 } },
  upsert: true
});

替换文档

// 替换整个文档(不推荐,会覆盖整个文档)
db.collection.save({
  _id: ObjectId("..."),  // 必须包含 _id
  newField1: "value1",
  newField2: "value2"
});

删除文档和集合

删除文档

// 删除匹配条件的所有文档
db.YOUR_TARGET_COLLECTION.remove({ field: value });

// 只删除一条匹配的文档
db.YOUR_TARGET_COLLECTION.deleteOne({ field: value });

// 删除所有匹配的文档
db.YOUR_TARGET_COLLECTION.deleteMany({ field: value });

删除集合

// 删除整个集合(包括所有文档)
db.YOUR_TARGET_COLLECTION.drop();

原文:
https://lizijie.github.io/2025/12/21/mongodb%E7%AC%94%E8%AE%B0.html

作者github:
https://github.com/lizijie </b>

PREVIOUS搭建loki日志聚合
NEXT记录乱七八糟的配置-window