《MongoDB 常用命令详解:从数据库操作到高级查询》
前言:案例背景
本文以“文章评论存储”为实战场景,基于以下数据模型展开命令讲解:
- 数据库:
articledb
(存储文章相关数据) - 集合:
comment
(存储文章评论,类似关系型数据库的“表”) - 字段结构:
字段名 | 类型 | 含义 | 备注 |
---|---|---|---|
_id | ObjectId/String | 主键 | MongoDB 自动生成或手动指定,确保唯一性 |
articleid | String | 文章 ID | 关联对应的文章 |
content | String | 评论内容 | 核心业务字段 |
userid | String | 评论人 ID | 关联用户表 |
nickname | String | 评论人昵称 | 冗余存储,减少关联查询 |
createdatetime | Date | 评论时间 | 支持时间范围查询 |
likenum | Int32 | 点赞数 | 需用 NumberInt() 声明整型 |
replynum | Int32 | 回复数 | 同上 |
state | String | 状态 | 1:可见;0:不可见 |
parentid | String | 上级 ID | 0 表示顶级评论,非 0 表示回复评论 |
一、数据库操作
MongoDB 的数据库操作包括“选择/创建”“查看”“删除”,核心是通过 use
命令切换上下文。
1.1 选择与创建数据库
语法:use 数据库名称
- 若数据库不存在,执行
use
后插入数据会自动创建; - 若数据库已存在,直接切换到该数据库。
示例:创建并切换到 articledb
数据库
use articledb
1.2 查看数据库
语法:
- 查看所有有权限的数据库:
show dbs
或show databases
- 查看当前正在使用的数据库:
db
注意:刚创建的数据库不会显示在 show dbs
结果中,需插入数据(创建集合并写入文档)后才会持久化显示。
示例:
// 查看所有数据库
show dbs
// 查看当前数据库
db // 输出:articledb
1.3 删除数据库
语法:db.dropDatabase()
- 仅删除当前正在使用的数据库;
- 需谨慎操作,删除后数据不可恢复。
示例:删除 articledb
数据库
use articledb // 先切换到目标数据库
db.dropDatabase() // 返回 { "dropped" : "articledb", "ok" : 1 } 表示成功
1.4 数据库命名规范
- 不能是空字符串或包含空格、
.
、$
、/
、\
、\0
(空字符); - 需全部小写,最多 64 字节;
- 保留数据库(不可随意操作):
admin
:权限根数据库,用户在此数据库添加后继承所有权限;local
:本地数据库,数据不复制,仅存储单节点私有数据;config
:分片集群专用,存储分片配置信息。
二、集合操作
集合(Collection)类似关系型数据库的“表”,支持显式创建和隐式创建(推荐)。
2.1 显式创建集合(了解)
语法:db.createCollection("集合名称")
- 适用于需提前配置集合属性(如分片、索引)的场景,常规开发很少用。
示例:创建 comment
集合
use articledb
db.createCollection("comment")
2.2 查看集合
语法:show collections
或 show tables
示例:查看 articledb
中的所有集合
use articledb
show collections // 输出:comment(若已创建)
2.3 隐式创建集合(推荐)
MongoDB 允许直接向不存在的集合插入文档,集合会自动创建,无需手动声明。
示例:向不存在的 comment
集合插入文档,自动创建集合
use articledb
// 插入文档时,若 comment 不存在则自动创建
db.comment.insert({"articleid":"100000","content":"今天天气真好"})
2.4 删除集合
语法:db.集合名称.drop()
- 删除后集合及所有文档永久删除,不可恢复。
示例:删除 comment
集合
use articledb
db.comment.drop() // 返回 true 表示成功,false 表示集合不存在
2.5 集合命名规范
- 不能是空字符串或包含
\0
(空字符); - 不能以
system.
开头(系统集合保留前缀); - 不能包含
$
(系统集合专用,用户集合避免使用)。
三、文档基本 CRUD 操作
文档(Document)是 MongoDB 的最小存储单位(类似关系型数据库的“行”),格式为 BSON(二进制 JSON)。
3.1 文档插入(Create)
支持单个文档插入和批量文档插入,核心命令为 insert()
和 insertMany()
。
3.1.1 单个文档插入
语法:
db.collection.insert(<document>, // 单个文档(BSON 格式){writeConcern: <document>, // 可选,写入确认机制ordered: <boolean> // 可选,仅数组插入有效,默认 true(有序插入)}
)
示例:向 comment
集合插入一条评论
use articledb
db.comment.insert({"articleid": "100000","content": "今天天气真好,阳光明媚","userid": "1001","nickname": "Rose","createdatetime": new Date(), // 插入当前时间"likenum": NumberInt(10), // 整型需用 NumberInt() 声明"state": null // 空值用 null
})
// 成功返回:WriteResult({ "nInserted" : 1 })
关键提示:
- 未指定
_id
时,MongoDB 自动生成ObjectId
作为主键; - 数字默认是
double
类型,存储整型需用NumberInt(整数)
或NumberLong(长整数)
; - 日期用
new Date()
生成(UTC 时间,可通过工具转换为本地时间)。
3.1.2 批量文档插入
语法:
db.collection.insertMany([ <document1>, <document2>, ... ], // 文档数组{writeConcern: <document>, // 可选,写入确认机制ordered: <boolean> // 可选,默认 true(有序插入,失败则终止)}
)
示例:批量插入 5 条评论(手动指定 _id
)
use articledb
db.comment.insertMany([{"_id": "1", // 手动指定主键(String 类型)"articleid": "100001","content": "我们不应该把清晨浪费在手机上,健康很重要","userid": "1002","nickname": "相忘于江湖","createdatetime": new Date("2019-08-05T22:08:15.522Z"),"likenum": NumberInt(1000),"state": "1"},{"_id": "2","articleid": "100001","content": "我夏天空腹喝凉开水,冬天喝温开水","userid": "1005","nickname": "伊人憔悴","createdatetime": new Date("2019-08-05T23:58:51.485Z"),"likenum": NumberInt(888),"state": "1"},{ "_id": "3", "articleid": "100001", "content": "我一直喝凉开水", "userid": "1004", "nickname": "杰克船长", "createdatetime": new Date("2019-08-06T01:05:06.321Z"), "likenum": NumberInt(666), "state": "1" },{ "_id": "4", "articleid": "100001", "content": "专家说不能空腹吃饭", "userid": "1003", "nickname": "凯撒", "createdatetime": new Date("2019-08-06T08:18:35.288Z"), "likenum": NumberInt(2000), "state": "1" },{ "_id": "5", "articleid": "100001", "content": "刚烧开的水千万不能喝,因为烫嘴", "userid": "1003", "nickname": "凯撒", "createdatetime": new Date("2019-08-06T11:01:02.521Z"), "likenum": NumberInt(3000), "state": "1" }
])
异常处理:批量插入若某条失败,ordered: true
会终止后续插入,可通过 try-catch
捕捉异常:
try {db.comment.insertMany([/* 文档数组 */]);
} catch (e) {print(e); // 打印错误信息,已插入成功的文档不会回滚
}
3.2 文档查询(Read)
核心命令为 find()
和 findOne()
,支持全量查询、条件查询和投影查询(指定返回字段)。
3.2.1 全量查询
语法:db.collection.find()
或 db.collection.find({})
- 返回集合中所有文档,默认显示
_id
字段。
示例:查询 comment
集合所有评论
use articledb
db.comment.find()
3.2.2 条件查询
语法:db.collection.find({查询条件})
- 查询条件为 BSON 格式,键为字段名,值为匹配条件。
常见场景:
- 等值查询:查询
userid = "1003"
的评论db.comment.find({userid: "1003"})
- 查询第一条匹配结果:用
findOne()
,返回单个文档(无需遍历)db.comment.findOne({userid: "1003"})
3.2.3 投影查询(指定返回字段)
语法:db.collection.find({查询条件}, {字段名: 1 或 0})
1
:显示该字段;0
:隐藏该字段;- 默认显示
_id
,若需隐藏需显式指定_id: 0
。
示例:
- 查询
userid = "1003"
的评论,仅显示userid
、nickname
和默认的_id
db.comment.find({userid: "1003"}, {userid: 1, nickname: 1})
- 隐藏
_id
,仅显示userid
和nickname
db.comment.find({userid: "1003"}, {userid: 1, nickname: 1, _id: 0})
3.3 文档更新(Update)
核心命令为 update()
,支持局部更新、批量更新和字段自增,需注意避免“覆盖更新”。
3.3.1 核心语法
db.collection.update(<query>, // 查询条件(匹配要更新的文档)<update>, // 更新内容(需用更新运算符,如 $set){upsert: <boolean>, // 可选,无匹配时是否创建新文档,默认 falsemulti: <boolean>, // 可选,是否更新所有匹配文档,默认 false(仅更新第一条)writeConcern: <document> // 可选,写入确认机制}
)
3.3.2 常见更新场景
-
覆盖更新(不推荐):直接替换整个文档(丢失未指定字段)
// 错误示例:更新 _id="1" 的文档,仅保留 likenum 字段,其他字段丢失 db.comment.update({_id: "1"}, {likenum: NumberInt(1001)})
-
局部更新(推荐):用
$set
运算符仅更新指定字段// 正确示例:更新 _id="2" 的文档,仅修改 likenum 为 889 db.comment.update({_id: "2"}, {$set: {likenum: NumberInt(889)}})
-
批量更新:设置
multi: true
,更新所有匹配文档// 更新所有 userid="1003" 的文档,将 nickname 改为“凯撒大帝” db.comment.update({userid: "1003"}, {$set: {nickname: "凯撒大帝"}}, {multi: true} )
-
字段自增/自减:用
$inc
运算符实现数值字段的增减// 对 _id="3" 的文档,likenum 自增 1(每次执行点赞数+1) db.comment.update({_id: "3"}, {$inc: {likenum: NumberInt(1)}}) // 自减示例:likenum 减 2 db.comment.update({_id: "3"}, {$inc: {likenum: NumberInt(-2)}})
3.4 文档删除(Delete)
核心命令为 remove()
,支持条件删除和全量删除,需谨慎操作。
3.4.1 核心语法
db.collection.remove(<query>) // query:删除条件,空对象 {} 表示删除所有
3.4.2 常见场景
-
条件删除:删除指定条件的文档
// 删除 _id="1" 的文档 db.comment.remove({_id: "1"})
-
全量删除(谨慎):删除集合中所有文档(集合结构保留)
// 危险!删除 comment 集合所有文档 db.comment.remove({})
注意:remove()
仅删除文档,不删除集合结构;若需删除集合及结构,用 db.collection.drop()
。
四、文档高级查询
包括统计查询、分页查询、排序查询、模糊查询、比较查询等,满足复杂业务场景。
4.1 统计查询
用 count()
方法统计匹配文档的数量,支持条件统计。
语法:db.collection.count(<query>)
query
:可选,统计符合条件的文档数;空则统计所有。
示例:
- 统计
comment
集合所有文档数db.comment.count()
- 统计
userid="1003"
的文档数db.comment.count({userid: "1003"})
4.2 分页查询
结合 skip()
(跳过指定数量文档)和 limit()
(返回指定数量文档)实现分页。
语法:db.collection.find().skip(跳过数).limit(每页条数)
- 分页公式:
skip((页码-1)*每页条数).limit(每页条数)
示例:每页显示 2 条评论,查询第 1-3 页
// 第 1 页:跳过 0 条,显示 2 条
db.comment.find().skip(0).limit(2)
// 第 2 页:跳过 2 条,显示 2 条
db.comment.find().skip(2).limit(2)
// 第 3 页:跳过 4 条,显示 2 条
db.comment.find().skip(4).limit(2)
4.3 排序查询
用 sort()
方法对查询结果排序,支持单字段和多字段排序。
语法:db.collection.find().sort({字段名: 1 或 -1})
1
:升序;-1
:降序;