第四章:CRUD 操作详解
掌握 MongoDB 的增删改查核心操作
4.1 Insert 操作
insertOne - 插入单文档
// 基本插入
db.users.insertOne({
username: "alice",
email: "alice@example.com",
age: 25
})
// 插入后获取返回结果
db.users.insertOne({
username: "bob",
email: "bob@example.com"
}).then(result => {
print("插入的文档 ID:", result.insertedId)
})
// 显式指定 _id
db.users.insertOne({
_id: "user_001",
username: "charlie",
email: "charlie@example.com"
})
insertMany - 批量插入
// 批量插入多个文档
db.users.insertMany([
{ username: "dave", email: "dave@example.com", age: 30 },
{ username: "eve", email: "eve@example.com", age: 28 },
{ username: "frank", email: "frank@example.com", age: 35 }
])
// 批量插入并设置有序/无序
db.users.insertMany(
[
{ username: "user1", email: "user1@example.com" },
{ username: "user2", email: "user2@example.com" }
],
{ ordered: false } // 无序插入,一个失败继续插入其他
)
// 有序插入(默认),遇到错误停止
db.users.insertMany(
[
{ username: "user1" },
{ _id: "duplicate_id", username: "user2" } // 会导致插入失败
],
{ ordered: true }
)
insert / insertMany(已废弃)
// 不推荐使用 insert,已废弃
db.users.insert({ username: "test" })
save 方法(已废弃)
// 不推荐使用 save,已废弃
// 建议使用 insertOne 或 replaceOne
db.users.save({ _id: ObjectId("..."), username: "updated" })
4.2 Query 操作
find - 查询文档
// 查询所有文档
db.users.find()
// 格式化输出
db.users.find().pretty()
// 限制返回字段(投影)
db.users.find(
{}, // 查询条件
{ username: 1, email: 1, _id: 0 } // 只返回 username 和 email
)
// 排除字段
db.users.find(
{},
{ password: 0, __v: 0 } // 排除 password 和 __v
)
// 嵌套字段投影
db.users.find(
{},
{ "profile.firstName": 1, "profile.lastName": 1 }
)
findOne - 查询单文档
// 查询单个文档
db.users.findOne({ username: "alice" })
// 查询并排序
db.users.findOne(
{ status: "active" },
{},
{ sort: { created_at: -1 } }
)
// 查询第一个文档
db.users.findOne()
查询条件操作符
| 操作符 |
说明 |
示例 |
$eq |
等于 |
{ age: { $eq: 25 } } |
$ne |
不等于 |
{ age: { $ne: 25 } } |
$gt |
大于 |
{ age: { $gt: 18 } } |
$gte |
大于等于 |
{ age: { $gte: 18 } } |
$lt |
小于 |
{ age: { $lt: 65 } } |
$lte |
小于等于 |
{ age: { $lte: 65 } } |
$in |
在数组中 |
{ status: { $in: ["active", "pending"] } } |
$nin |
不在数组中 |
{ status: { $nin: ["deleted"] } } |
// 比较操作符示例
db.users.find({ age: { $gte: 18, $lte: 65 } })
db.users.find({
status: { $in: ["active", "pending"] }
})
db.users.find({
username: { $nin: ["admin", "root"] }
})
// 使用 $eq 的完整形式
db.users.find({ username: { $eq: "alice" } })
逻辑操作符
| 操作符 |
说明 |
示例 |
$and |
逻辑与 |
{ $and: [{ a: 1 }, { b: 2 }] } |
$or |
逻辑或 |
{ $or: [{ a: 1 }, { b: 2 }] } |
$not |
逻辑非 |
{ age: { $not: { $gte: 18 } } } |
$nor |
逻辑或非 |
{ $nor: [{ a: 1 }, { b: 2 }] } |
// AND 操作
db.users.find({
$and: [
{ age: { $gte: 18 } },
{ status: "active" }
]
})
// OR 操作
db.users.find({
$or: [
{ username: "alice" },
{ email: "alice@example.com" }
]
})
// 组合条件
db.users.find({
$and: [
{ $or: [{ age: { $lte: 18 } }, { age: { $gte: 65 } }] },
{ status: "active" }
]
})
// NOR 示例
db.users.find({
$nor: [
{ status: "banned" },
{ role: "admin" }
]
})
字段操作符
| 操作符 |
说明 |
示例 |
$exists |
字段存在 |
{ email: { $exists: true } } |
$type |
字段类型 |
{ age: { $type: "number" } } |
$regex |
正则匹配 |
{ username: { $regex: "^admin" } } |
// 字段存在
db.users.find({ phone: { $exists: true } })
db.users.find({ profile: { $exists: false } })
// 字段类型
db.users.find({ age: { $type: "number" } })
db.users.find({ _id: { $type: "objectId" } })
// 正则表达式(区分大小写)
db.users.find({ username: { $regex: "^admin", $options: "i" } })
// 使用正则的简洁语法
db.users.find({ email: /@gmail\.com$/ })
数组操作符
| 操作符 |
说明 |
示例 |
$all |
包含所有元素 |
{ tags: { $all: ["a", "b"] } } |
$elemMatch |
数组元素匹配 |
{ scores: { $elemMatch: { $gt: 80 } } } |
$size |
数组长度 |
{ tags: { $size: 3 } } |
// 查询包含特定标签的文章
db.articles.find({ tags: { $all: ["mongodb", "database"] } })
// 查询数组中至少有一个元素满足条件
db.scores.find({
results: {
$elemMatch: {
subject: "Math",
score: { $gte: 90 }
}
}
})
// 查询标签数量为 3 的文档
db.articles.find({ tags: { $size: 3 } })
// 查询空数组
db.articles.find({ tags: { $size: 0 } })
内嵌文档查询
// 精确匹配内嵌文档(字段顺序必须一致)
db.users.find({ profile: { firstName: "Alice", lastName: "Smith" } })
// 查询嵌套字段(使用点号)
db.users.find({ "profile.address.city": "Beijing" })
db.users.find({ "profile.phone.mobile": { $exists: true } })
// 嵌套数组查询
db.orders.find({
"items.product_id": ObjectId("...")
})
4.3 Update 操作
updateOne - 更新单文档
// 基本更新
db.users.updateOne(
{ username: "alice" },
{ $set: { email: "new_email@example.com" } }
)
// 使用 updateOne 返回结果
db.users.updateOne(
{ username: "alice" },
{ $set: { status: "inactive" } }
).then(result => {
print("匹配文档数:", result.matchedCount)
print("修改文档数:", result.modifiedCount)
})
updateMany - 批量更新
// 批量更新
db.users.updateMany(
{ status: "pending" },
{ $set: { status: "active", updated_at: new Date() } }
)
// 更新多个字段
db.products.updateMany(
{ category: "Electronics" },
{
$set: {
tax_rate: 0.13,
currency: "USD"
}
}
)
字段操作符
| 操作符 |
说明 |
示例 |
$set |
设置字段值 |
{ $set: { field: value } } |
$unset |
删除字段 |
{ $unset: { field: 1 } } |
$rename |
重命名字段 |
{ $rename: { old: new } } |
$inc |
递增/递减 |
{ $inc: { count: 1 } } |
$mul |
乘 |
{ $mul: { price: 1.1 } } |
$setOnInsert |
仅插入时设置 |
{ $setOnInsert: { created: new Date() } } |
// $set - 设置字段
db.users.updateOne(
{ _id: ObjectId("...") },
{ $set: { "profile.avatar": "https://..." } }
)
// $unset - 删除字段
db.users.updateOne(
{ _id: ObjectId("...") },
{ $unset: { temp_field: 1 } }
)
// $rename - 重命名字段
db.users.updateMany(
{},
{ $rename: { "first_name": "firstName", "last_name": "lastName" } }
)
// $inc - 递增
db.counters.updateOne(
{ _id: "order_id" },
{ $inc: { seq: 1 } }
)
// $mul - 乘法
db.products.updateMany(
{},
{ $mul: { price: 1.1 } } // 所有价格涨 10%
)
数组操作符
| 操作符 |
说明 |
示例 |
$push |
添加元素 |
{ $push: { tags: "new" } } |
$pop |
删除元素 |
{ $pop: { tags: 1 } } |
$pull |
移除匹配元素 |
{ $pull: { tags: "old" } } |
$addToSet |
添加唯一元素 |
{ $addToSet: { tags: "new" } } |
$pull + $each |
批量移除 |
{ $pull: { tags: { $in: ["a", "b"] } } } |
// $push - 添加元素
db.users.updateOne(
{ _id: ObjectId("...") },
{ $push: { tags: "developer" } }
)
// $push + $each - 批量添加
db.users.updateOne(
{ _id: ObjectId("...") },
{ $push: { tags: { $each: ["python", "golang"] } } }
)
// $addToSet - 添加唯一元素(不会重复)
db.users.updateOne(
{ _id: ObjectId("...") },
{ $addToSet: { skills: "mongodb" } }
)
// $pop - 删除最后一个元素 (1) 或第一个元素 (-1)
db.lists.updateOne(
{ _id: ObjectId("...") },
{ $pop: { items: 1 } }
)
// $pull - 移除匹配的元素
db.users.updateOne(
{ _id: ObjectId("...") },
{ $pull: { tags: "old_tag" } }
)
// $pull + $in - 批量移除
db.users.updateOne(
{ _id: ObjectId("...") },
{ $pull: { tags: { $in: ["temp", "unused"] } } }
)
替换文档 - replaceOne
// 替换整个文档(保留 _id)
db.users.replaceOne(
{ _id: ObjectId("...") },
{
username: "alice",
email: "alice@example.com",
status: "active",
updated_at: new Date()
}
)
4.4 Delete 操作
deleteOne - 删除单文档
// 删除单个文档
db.users.deleteOne({ username: "alice" })
// 删除结果
db.users.deleteOne({ _id: ObjectId("...") }).then(result => {
print("删除文档数:", result.deletedCount)
})
deleteMany - 批量删除
// 批量删除
db.users.deleteMany({ status: "inactive", last_login: { $lt: ISODate("2023-01-01") } })
// 删除所有文档(谨慎使用)
db.temp_data.deleteMany({})
drop - 删除集合
// 删除整个集合(包括索引)
db.users.drop()
// 检查是否删除成功
db.getCollectionNames() // users 应该不在列表中
dropDatabase - 删除数据库
// 删除当前数据库
db.dropDatabase()
// 删除指定数据库
use mydb
db.dropDatabase()
4.5 查询选项
limit 和 skip
// 限制返回数量
db.users.find().limit(10)
// 跳过前 N 条(分页)
db.users.find().skip(20).limit(10)
// 分页查询(每页 10 条)
const page = 2
const pageSize = 10
db.users.find().skip((page - 1) * pageSize).limit(pageSize)
sort - 排序
// 单字段排序(1 升序,-1 降序)
db.users.find().sort({ created_at: -1 })
// 多字段排序
db.articles.find().sort({
category: 1,
view_count: -1,
created_at: -1
})
// 结合其他操作
db.users.find(
{ status: "active" },
{},
{ sort: { created_at: -1 }, limit: 10 }
)
countDocuments - 计数
// 统计满足条件的文档数
db.users.countDocuments({ status: "active" })
// 统计集合总文档数
db.users.countDocuments({})
// 使用 estimatedDocumentCount(更快,但不接受查询条件)
db.users.estimatedDocumentCount()
distinct - 去重
// 获取字段的所有不重复值
db.users.distinct("country")
// 带查询条件的去重
db.orders.distinct("status", { created_at: { $gte: ISODate("2024-01-01") } })
// 数组字段去重
db.articles.distinct("tags")
4.6 游标操作
// 遍历游标
const cursor = db.users.find({ status: "active" })
while (cursor.hasNext()) {
printjson(cursor.next())
}
// 使用 forEach
db.users.find().forEach(user => {
print(`User: ${user.username}`)
})
// 使用 toArray
const users = db.users.find().toArray()
// 限制和转换
const usernames = db.users.find({}, { username: 1, _id: 0 }).toArray()
💡 实践提示
- 使用投影减少数据传输:只查询需要的字段,减少网络开销
- 合理使用索引字段查询:确保查询条件包含索引字段
- 分页查询时使用游标分页:避免 skip 大量数据导致的性能问题
- 更新前先查询:确保更新的文档存在
- 使用
$set 避免覆盖整个文档:除非你确实想替换整个文档
📚 继续学习