Mongodb的基本操作

前言:为什么选择 MongoDB?
记得第一次接触 MongoDB 是在 2013 年的一个项目中。当时我们正在为一个电商后台做数据管理,传统的 MySQL 数据库在处理商品属性这种高度动态、结构不固定的数据时显得力不从心。每次新增一个商品类型,都要反复修改表结构,ALTER TABLE 成了我们最不想看到的操作。
就在那段时间,团队里一位资深开发向我推荐了 MongoDB。他说:”试试 NoSQL 吧,MongoDB 的文档存储模型,就像是在数据库里直接存 JSON 对象,灵活得很。”
这句话彻底改变了我对数据库的认知。经过一段时间的学习和实践,我将 MongoDB 的常用操作整理成这篇笔记,希望也能帮助到正在探索 NoSQL 世界的你。

MongoDB 的核心思想
在学习具体操作之前,先理解 MongoDB 的设计哲学非常重要。与传统的关系型数据库不同,MongoDB 采用了 文档型存储模型(Document-Oriented Storage)。简单来说,它把数据以类似 JSON 的 BSON 格式存储在数据库中,每条记录称为一个”文档”(Document),多个文档组成一个”集合”(Collection)。
这种设计有几个天然优势:
- 灵活的模式(Schema-less):不需要预先定义表结构,每个文档可以有不同的字段
- 嵌套存储:支持直接在文档中存储嵌套对象和数组,避免了传统数据库中复杂的 JOIN 操作
- 高性能:BSON 格式的二进制编码使得读写效率非常高,特别是在大数据量场景下
下面,我就把日常开发中最常用的 MongoDB 操作逐一展开说明。
1. 存储嵌套的对象
MongoDB 最吸引人的特性之一就是可以直接存储嵌套的 JSON 对象。这在实际开发中非常实用,比如存储一个用户的完整地址信息:
1 | db.mydb.save({ |
解读:这条语句向 mydb 集合中插入了一条文档,其中 address 是一个嵌套对象,包含了城市和邮编信息;phone 是一个数组,存储了多个电话号码。在传统的关系型数据库中,这通常需要两张表(用户表和地址表)加上外键关联才能实现,而在 MongoDB 中只需要一条语句。
2. 存储数组对象
数组在 MongoDB 中是一等公民。来看一个存储用户邮件地址列表的例子:
1 | db.mydb.save({ |
解读:Al 字段是一个字符串数组,直接存储了用户关联的所有邮箱地址。这种设计特别适合存储标签列表、兴趣爱好、关联账号等场景。
3. 条件更新:不存在则插入
这是 MongoDB 中非常强大的一个操作 —— upsert(update + insert)。它可以根据查询条件更新记录,如果记录不存在则自动插入:
1 | db.mydb.update( |
解读:
{'yy': 5}是查询条件,查找yy字段等于 5 的文档{'$set': {'xx': 2}}是更新操作,将xx字段设置为 2upsert: true表示如果没有找到匹配的文档,则插入一条新记录multi: true表示更新所有匹配的文档,而不是只更新第一条
实际场景:这个操作在计数器、状态同步、缓存更新等场景中非常有用。比如记录用户的登录次数,如果用户首次登录则插入记录,否则累加计数。

4. 删除满足条件的记录
1 | db.mydb.remove({'yy': 5}) |
解读:删除 mydb 集合中所有 yy 字段等于 5 的文档。这是带条件的删除操作,在实际使用中务必谨慎,建议先通过 find() 确认要删除的数据范围。
5. 删除所有记录
1 | db.mydb.remove() |
解读:清空集合中的所有文档。这是一个危险操作,生产环境中应严格避免。如果你只是想删除整个集合,更推荐使用 db.mydb.drop(),它会直接删除集合及其索引,效率更高。
6. 查询有限的数据
1 | db.mydb.find().limit(10) |
解读:limit() 方法用于限制查询返回的文档数量。在分页查询、排行榜、最新记录等场景中非常常用。比如获取最新的 10 条日志、分页显示每页 20 条数据等。
7. 查询单条数据
1 | db.mydb.findOne() |
解读:findOne() 返回查询结果中的第一条文档。与 find().limit(1) 的区别在于,findOne() 直接返回文档对象,而不是游标(cursor)。这在查询用户详情、单条配置等场景中非常高效。
8. 排序操作
MongoDB 支持对查询结果进行排序:
1 | // 按 Dt 字段降序排列 |
解读:
sort()方法接受一个排序规则对象,键为字段名,值为排序方向1表示升序(ASC),-1表示降序(DESC)- 第二个例子是典型的使用场景:获取最新(或最大)的一条记录
9. 统计记录数
1 | db.mydb.count() |
解读:返回集合中文档的总数。可以配合查询条件使用,如 db.mydb.count({'status': 'active'}) 统计活跃用户数。
注意:在 MongoDB 3.2 之后,推荐使用 countDocuments() 替代 count(),以获得更准确的统计结果。
10. 去重查询
1 | db.mydb.distinct('msg') |
解读:对指定字段进行去重,返回所有不重复的值。比如获取所有不重复的消息类型、所有唯一的标签等。
11. 范围查询:大于等于
1 | db.mydb.find({"timestamp": {"$gte": 2}}) |
解读:查询 timestamp 字段大于等于 2 的所有文档。MongoDB 提供了丰富的比较操作符:
| 操作符 | 含义 |
|---|---|
$gt |
大于 |
$gte |
大于等于 |
$lt |
小于 |
$lte |
小于等于 |
$ne |
不等于 |
$in |
在数组中 |
$nin |
不在数组中 |
12. 嵌套对象的查找
1 | db.mydb.find({'address.city': 'beijing'}) |
解读:这是 MongoDB 查询中非常优雅的一个特性 —— 使用点号(.)来访问嵌套文档中的字段。上面的语句查找所有 address 对象中 city 为 beijing 的文档。
这种方式同样适用于数组元素的查询,比如 db.mydb.find({'tags': 'mongodb'}) 可以查找 tags 数组中包含 mongodb 的所有文档。
13. 查询所有记录
1 | db.mydb.find() |
解读:返回集合中的所有文档。相当于 SQL 中的 SELECT * FROM table。在数据量大的集合上执行此操作时要注意性能影响,建议始终配合 limit() 使用。

实践中的心得体会
在使用 MongoDB 的这段时间里,我有几点深刻的体会想分享:
第一,JSON 思维是核心。 使用 MongoDB 最大的转变是从”表”的思维切换到”文档”的思维。在设计数据结构时,要思考”这条数据自然应该是什么样子”,而不是”需要几张表来存储”。这种思维转变一开始可能不太习惯,但一旦适应了,你会发现数据建模变得异常自然和直观。
第二,索引不能忽视。 虽然 MongoDB 的查询性能很高,但这并不意味着可以忽略索引。对于频繁查询的字段、排序字段、范围查询字段,都应该建立合适的索引。我曾在一次线上事故中深有体会:一个没有索引的大集合查询导致整个接口响应超时,加上索引后响应时间从 15 秒降到了 50 毫秒。
第三,数据一致性需要额外关注。 MongoDB 默认提供的是”最终一致性”,在分布式环境下,这可能会带来一些意想不到的问题。如果你的业务场景对数据一致性要求极高,建议在写入时设置合适的 writeConcern 级别。
总结
MongoDB 的存储方式本质上就是 JSON(BSON)格式,这种设计使得数据存储和读取都非常高效。它的灵活性和高性能使其成为处理非结构化数据、快速迭代项目的理想选择。
从我的学习经历来看,MongoDB 的操作语法虽然和 SQL 有很大不同,但逻辑是相通的。只要理解了文档模型的核心概念,再加上不断的实践,很快就能上手。对于正在考虑技术选型的开发者来说,MongoDB 绝对是一个值得认真评估的选项。
这篇笔记写于 2013 年,记录了我初识 MongoDB 时的学习心得。如今 MongoDB 已经发展到了更新的版本,增加了聚合管道、事务支持等更多强大的功能,但其核心的文档存储理念始终未变。技术的形式在变,但灵活高效的设计哲学值得持续学习和传承。







