MongoDB 简介

集合与增删改查

学会数据库与集合的概念,掌握 insertOne、find、updateOne、deleteOne 四种基本操作。

🎯 引言

上一篇我们已经用 Docker 跑起了 mongo-demo 容器,并用 mongosh 连上了 MongoDB。学完这篇文章,你能理解数据库和集合的概念,并完成数据的插入、查询、修改、删除四种基本操作,也就是大家常说的 CRUD。这四种操作是日常使用 MongoDB 的核心,后面的课程都建立在它们之上。

本文所有操作都在 mongosh 中执行。如果还没连上,请先运行:

docker exec -it mongo-demo mongosh -u root -p 123456 --authenticationDatabase admin

🧱 数据库与集合

一个 MongoDB 服务里可以放很多个数据库(Database),每个数据库相互独立。可以把它理解成 Excel:一个数据库就是一个 Excel 文件,里面的每张工作表就是一个集合(Collection),而集合里的一条条数据叫文档(Document)

切换到本课程的示例数据库 blog_demo

use blog_demo
如果 blog_demo 不存在,use 也能执行成功。这是 MongoDB 的特点:数据库和集合都不需要提前创建,插入第一条数据时才会真正生成。你可以把 use blog_demo 理解成「声明接下来要操作它」,等真正写入数据那一刻,MongoDB 才会把它建出来。

集合也一样,无需提前创建。比如往 user 集合插入第一条数据时,这个集合就会自动出现。如果确实想手动建一个集合(比如配置一些集合级的选项),也可以用:

db.createCollection('user')
use blog_demo 只对当前连接生效。如果你关掉 mongosh 重新连接,需要再执行一次,否则 mongosh 不知道你要操作哪个数据库。

这里的 db 是 mongosh 提供的一个变量,代表「当前数据库」,后面的增删改查都会用到它:db.user 就表示当前数据库下的 user 集合。


✨ 插入数据 insertOne

集合是空的,我们先往里放数据。插入一条数据用 insertOne,传一个对象进去:

db.user.insertOne({ username: '张三', age: 25, city: '北京' })

执行成功后会返回类似这样的结果:

{
    acknowledged: true,
    insertedId: ObjectId('66f1a2b3c4d5e6f7a8b9c0d1')
}
  • acknowledged: true 表示写入已被确认。
  • insertedId 是这条文档的 _id,由 MongoDB 自动生成,全局唯一,相当于每条数据的身份证号,你不用自己准备。
ObjectId('...') 里的长串字符是你机器上生成的随机值,和本文示例不同是正常的。以后可以根据 _id 精确定位某一条文档。

一次插入多条数据用 insertMany,传一个数组:

db.user.insertMany([
    { username: '李四', age: 30, city: '上海' },
    { username: '王五', age: 22, city: '广州' },
    { username: '赵六', age: 28, city: '深圳' },
])

返回结果里会有一个 insertedIds 对象,列出每条新文档的 _id


💡 查询数据 find

查询用 find,这是日常使用频率很高的操作。不带条件时查出集合里的全部数据:

db.user.find()

执行后能看到刚才插入的四条文档,每条都带着自动生成的 _idfind 默认返回全部字段,不需要像其他数据库那样指定列。

只想查一条时,用 findOne 并写上条件:

db.user.findOne({ username: '张三' })

第一个参数是查询条件,写成一个对象:{ username: '张三' } 表示「username 字段等于张三」。find 也可以带同样的条件,区别是 find 返回所有匹配的文档,findOne 只返回匹配到的第一条:

db.user.find({ city: '上海' })

本文先会用「字段等于某个值」这种简单条件,更丰富的条件写法(大于、小于、多条件组合等)是下一篇的主角。


⚡ 修改数据 updateOne

已有数据写错了怎么办?用 updateOne 来改。比如张三搬到了杭州:

db.user.updateOne({ username: '张三' }, { $set: { city: '杭州' } })

它接收两个参数:

  • 第一个参数是条件,和 find 的条件写法一样,定位要改哪些文档。
  • 第二个参数是修改内容$set 表示「把指定字段改成指定值」,没有写在 $set 里的字段保持原样。

执行后返回的结果里有几个值得关注的数字:

{
    acknowledged: true,
    matchedCount: 1,
    modifiedCount: 1,
    // ...其他字段省略
}
  • matchedCount:条件匹配到了几条文档。
  • modifiedCount:实际被改动的有几条。如果新值和旧值一样,匹配到了但不会重复修改,这个数字就是 0。

updateOne 只改匹配到的第一条,想把符合条件的文档全部改掉,用 updateMany

db.user.updateMany({ city: '广州' }, { $set: { city: '珠海' } })
修改时第二个参数一定要写 $set 如果直接写 db.user.updateOne({ username: '张三' }, { city: '杭州' }),MongoDB 会把它理解成「用 { city: '杭州' } 这个文档整体替换掉原来的文档」,结果是 usernameage 字段全部丢失,只剩一个 city。这是新手很容易踩的坑:想改一个字段,却顺手把其他字段弄没了。

🪤 删除数据 deleteOne

删除数据用 deleteOnedeleteMany。比如把赵六这条数据删掉:

db.user.deleteOne({ username: '赵六' })

返回结果里的 deletedCount 告诉你实际删掉了几条。deleteOne 只删匹配到的第一条,deleteMany 会删掉所有匹配的文档:

db.user.deleteMany({ city: '珠海' })

删除是不可逆的,执行前建议先用同样条件的 find 查一遍,确认要删的就是这些数据:

db.user.find({ city: '珠海' })

确认结果没问题,再执行对应的 deleteMany

不带条件的 updateMany 和 deleteMany 会作用于整个集合! 比如 db.user.deleteMany({}) 会把集合里的所有文档删光。请养成习惯:执行删除前先用同样的条件 find 一遍,确认匹配到的就是要处理的数据。

🧾 小节总结

  • use blog_demo 切换数据库,数据库和集合在插入第一条数据时才真正创建。
  • insertOne 插入一条文档,insertMany 一次插入多条;_id 由 MongoDB 自动生成,通过 insertedId 可以拿到。
  • find() 查全部,findOne({ username: '张三' }) 查一条;查询条件写成对象,find 默认返回全部字段。
  • updateOneupdateMany 修改数据,第二个参数用 $set 指定要改的字段;结果里的 matchedCountmodifiedCount 告诉你匹配了几条、改了几条。
  • deleteOnedeleteMany 删除数据;不带条件的批量操作会作用于整个集合,删除前先用同样条件 find 一遍确认。

❓ 知识问答

Q1:插入数据时必须提前定义好字段吗?

不用。MongoDB 的集合没有固定的字段结构,插入什么字段就存什么字段。不过实际项目里同一个集合的文档还是建议保持一致的字段,代码维护起来更轻松。

Q2:_id 可以自己指定吗?

可以,插入时自己传一个 _id 字段即可,但必须保证唯一,重复会报错。一般直接让 MongoDB 自动生成就好。

Q3:find 查出来数据太多,屏幕看不完怎么办?

mongosh 会分页显示,输入 it(iterate 的缩写)并回车可以翻下一页。实际开发中通常会配合条件和数量限制来查询,后面的篇章会讲到。

Q4:updateOne 时条件匹配到了多条文档,会发生什么?

只会修改匹配到的第一条,其余不动。想全部修改就改用 updateMany。拿不准匹配了多少条时,先用同样的条件 find 一下。

Q5:修改之后怎么确认改成功了?

除了看返回结果里的 modifiedCount,再用 find 把对应文档查出来看一眼即可。养成「改完查一下」的习惯,能及早发现条件写错的问题。


🧪 小练习

user 集合中完成下面两步操作:

  1. 插入一条你自己的数据(用户名随意,年龄和城市填真实的)。
// 请在这里编写代码
  1. 把上一步插入的这条数据的城市改成「成都」,然后把它查询出来确认。
// 请在这里编写代码

🎉 恭喜你已经掌握集合与增删改查技能啦!下一篇我们学习条件查询,看看如何用更丰富的条件(比较、多条件组合等)从一堆文档里精确找出你想要的那部分。