Appearance
文档操作
文档(Document)是MongoDB中数据的基本单位,类似于关系数据库中的行。本章将详细介绍文档的插入、查询、更新和删除操作。
文档结构
文档基本概念
javascript
// MongoDB文档是键值对的集合,使用BSON格式存储
// 基本文档结构
{
"_id": ObjectId("..."), // 文档唯一标识,自动生成
"name": "张三", // 字符串字段
"age": 25, // 数字字段
"active": true // 布尔字段
}
// 文档特点:
// 1. 字段名必须是字符串
// 2. 字段名不能包含$和.字符
// 3. 字段名不能以$开头
// 4. _id字段是保留字段,用作主键
// 5. 文档中不能有重复的字段名
// 支持的数据类型
{
"_id": ObjectId("507f1f77bcf86cd799439011"), // ObjectId
"string": "字符串", // 字符串
"int": NumberInt(42), // 32位整数
"long": NumberLong(42), // 64位整数
"double": 3.14, // 浮点数
"decimal": NumberDecimal("3.14159"), // 高精度小数
"boolean": true, // 布尔值
"date": ISODate("2024-01-01T00:00:00Z"), // 日期
"null": null, // null值
"array": [1, 2, 3], // 数组
"object": { "key": "value" }, // 嵌套文档
"binary": BinData(0, "aGVsbG8="), // 二进制数据
"regex": /^pattern$/, // 正则表达式
"code": Code("function() {}") // JavaScript代码
}插入文档
insertOne - 插入单个文档
javascript
// 插入单个文档
db.users.insertOne({
name: "张三",
age: 25,
email: "zhangsan@example.com",
hobbies: ["阅读", "编程"],
address: {
city: "北京",
street: "朝阳路"
},
createdAt: new Date()
})
// 输出示例:
// {
// acknowledged: true,
// insertedId: ObjectId("65a1b2c3d4e5f6g7h8i9j0k1")
// }
// 插入时指定_id
db.users.insertOne({
_id: "user001", // 自定义_id
name: "李四",
age: 30
})
// 如果_id已存在,会报错
// 插入文档的选项
db.users.insertOne(
{ name: "王五", age: 28 },
{
writeConcern: { w: "majority", j: true }, // 写入关注级别
ordered: true // 是否按顺序执行
}
)insertMany - 批量插入文档
javascript
// 批量插入多个文档
db.users.insertMany([
{ name: "用户1", age: 20, city: "北京" },
{ name: "用户2", age: 25, city: "上海" },
{ name: "用户3", age: 30, city: "广州" }
])
// 输出示例:
// {
// acknowledged: true,
// insertedIds: {
// '0': ObjectId("..."),
// '1': ObjectId("..."),
// '2': ObjectId("...")
// }
// }
// 批量插入选项
db.users.insertMany(
[
{ name: "用户A", age: 22 },
{ name: "用户B", age: 23 },
{ _id: "user001", name: "用户C", age: 24 } // 如果_id冲突
],
{ ordered: false } // 即使某条失败,继续插入其他文档
)
// ordered: true(默认)- 遇到错误停止
// ordered: false - 遇到错误继续插入其他文档insert - 兼容方法
javascript
// insert方法(已弃用,但仍可用)
// 可以插入单个或多个文档
// 插入单个文档
db.users.insert({ name: "测试用户", age: 20 })
// 插入多个文档
db.users.insert([
{ name: "批量用户1", age: 21 },
{ name: "批量用户2", age: 22 }
])批量插入最佳实践
javascript
// 批量插入的最佳实践
// 1. 分批插入大量数据
var batchSize = 1000;
var totalDocs = 10000;
for (var i = 0; i < totalDocs; i += batchSize) {
var batch = [];
for (var j = 0; j < batchSize && i + j < totalDocs; j++) {
batch.push({
name: "用户" + (i + j),
age: Math.floor(Math.random() * 50) + 18,
createdAt: new Date()
});
}
db.users.insertMany(batch);
print("已插入 " + Math.min(i + batchSize, totalDocs) + " 条文档");
}
// 2. 使用ordered: false提高性能
db.users.insertMany(largeArray, { ordered: false })
// 3. 关闭索引后批量插入(大量数据时)
db.users.dropIndexes(); // 删除非必要索引
db.users.insertMany(largeArray);
db.users.createIndex({ name: 1 }); // 重建索引查询文档
find - 查询多个文档
javascript
// 查询所有文档
db.users.find({})
// 输出示例(使用pretty()格式化):
// { "_id" : ObjectId("..."), "name" : "张三", "age" : 25 }
// { "_id" : ObjectId("..."), "name" : "李四", "age" : 30 }
// 格式化输出
db.users.find({}).pretty()
// 条件查询
db.users.find({ age: 25 }) // 查询age等于25的文档
db.users.find({ "address.city": "北京" }) // 查询嵌套字段
// 指定返回字段(投影)
db.users.find(
{ age: { $gte: 20 } }, // 查询条件
{ name: 1, age: 1, _id: 0 } // 只返回name和age,不返回_id
)
// 查询结果计数
db.users.find({ age: { $gte: 20 } }).count()
// 或
db.users.countDocuments({ age: { $gte: 20 } })findOne - 查询单个文档
javascript
// 查询单个文档
db.users.findOne({ name: "张三" })
// 输出示例:
// {
// "_id": ObjectId("..."),
// "name": "张三",
// "age": 25,
// "email": "zhangsan@example.com"
// }
// 查询第一个匹配的文档
db.users.findOne({ age: { $gte: 20 } })
// 指定返回字段
db.users.findOne(
{ name: "张三" },
{ name: 1, email: 1, _id: 0 }
)查询操作符
javascript
// 比较操作符
db.users.find({ age: { $eq: 25 } }) // 等于
db.users.find({ age: { $ne: 25 } }) // 不等于
db.users.find({ age: { $gt: 20 } }) // 大于
db.users.find({ age: { $gte: 20 } }) // 大于等于
db.users.find({ age: { $lt: 30 } }) // 小于
db.users.find({ age: { $lte: 30 } }) // 小于等于
db.users.find({ age: { $in: [20, 25, 30] } }) // 在列表中
db.users.find({ age: { $nin: [20, 25, 30] } }) // 不在列表中
// 逻辑操作符
db.users.find({
$and: [
{ age: { $gte: 20 } },
{ city: "北京" }
]
}) // 与操作
db.users.find({
$or: [
{ city: "北京" },
{ city: "上海" }
]
}) // 或操作
db.users.find({
age: { $not: { $gt: 30 } }
}) // 非操作
db.users.find({
age: { $nor: [{ $lt: 20 }, { $gt: 50 }] }
}) // 既不...也不...
// 存在性检查
db.users.find({ email: { $exists: true } }) // 字段存在
db.users.find({ email: { $exists: false } }) // 字段不存在
// 类型检查
db.users.find({ age: { $type: "int" } }) // 类型为int
db.users.find({ age: { $type: 16 } }) // 类型码16为int查询结果处理
javascript
// 限制返回数量
db.users.find().limit(10) // 只返回前10条
// 跳过指定数量
db.users.find().skip(10) // 跳过前10条
// 分页查询
var page = 2;
var pageSize = 10;
db.users.find().skip((page - 1) * pageSize).limit(pageSize)
// 排序
db.users.find().sort({ age: 1 }) // 按age升序
db.users.find().sort({ age: -1 }) // 按age降序
db.users.find().sort({ age: -1, name: 1 }) // 多字段排序
// 组合使用
db.users.find({ age: { $gte: 20 } })
.sort({ age: -1 })
.skip(0)
.limit(10)
// 遍历查询结果
db.users.find({ age: { $gte: 20 } }).forEach(function(user) {
print("用户: " + user.name + ", 年龄: " + user.age);
})
// 将结果转为数组
var users = db.users.find({ age: { $gte: 20 } }).toArray()更新文档
updateOne - 更新单个文档
javascript
// 更新单个文档
// 使用$set更新字段
db.users.updateOne(
{ name: "张三" }, // 查询条件
{ $set: { age: 26 } } // 更新操作
)
// 输出:{ acknowledged: true, matchedCount: 1, modifiedCount: 1 }
// 更新多个字段
db.users.updateOne(
{ name: "张三" },
{ $set: { age: 26, city: "上海", email: "newemail@example.com" } }
)
// 更新嵌套字段
db.users.updateOne(
{ name: "张三" },
{ $set: { "address.city": "深圳" } }
)
// 使用$inc增加数值
db.users.updateOne(
{ name: "张三" },
{ $inc: { age: 1 } } // age加1
)
// 使用$mul乘以数值
db.users.updateOne(
{ name: "张三" },
{ $mul: { salary: 1.1 } } // salary乘以1.1
)
// 使用$rename重命名字段
db.users.updateOne(
{ name: "张三" },
{ $rename: { "oldField": "newField" } }
)
// 使用$unset删除字段
db.users.updateOne(
{ name: "张三" },
{ $unset: { tempField: "" } } // 删除tempField字段
)
// 使用$currentDate设置当前日期
db.users.updateOne(
{ name: "张三" },
{ $currentDate: { updatedAt: true } }
)
// 如果不存在则插入(upsert)
db.users.updateOne(
{ name: "新用户" },
{ $set: { name: "新用户", age: 20 } },
{ upsert: true }
)updateMany - 批量更新文档
javascript
// 批量更新文档
// 更新所有符合条件的文档
db.users.updateMany(
{ city: "北京" }, // 查询条件
{ $set: { region: "华北" } } // 更新操作
)
// 输出:{ acknowledged: true, matchedCount: 100, modifiedCount: 100 }
// 批量增加数值
db.users.updateMany(
{ department: "技术部" },
{ $inc: { salary: 1000 } }
)
// 批量添加数组元素
db.users.updateMany(
{ city: "北京" },
{ $push: { tags: "首都" } }
)
// 批量删除数组元素
db.users.updateMany(
{},
{ $pull: { tags: "临时标签" } }
)replaceOne - 替换文档
javascript
// 替换整个文档(除了_id)
db.users.replaceOne(
{ name: "张三" }, // 查询条件
{ // 新文档内容
name: "张三",
age: 30,
city: "深圳",
updatedAt: new Date()
}
)
// 注意:replaceOne会完全替换文档,原有字段会被删除数组更新操作符
javascript
// 数组更新操作符
// $push - 添加元素到数组
db.users.updateOne(
{ name: "张三" },
{ $push: { hobbies: "游泳" } }
)
// $push添加多个元素
db.users.updateOne(
{ name: "张三" },
{ $push: { hobbies: { $each: ["游泳", "跑步", "健身"] } } }
)
// $push并限制数组长度
db.users.updateOne(
{ name: "张三" },
{
$push: {
logs: {
$each: ["log1", "log2"],
$slice: -10 // 只保留最后10个元素
}
}
}
)
// $addToSet - 添加元素(不存在时才添加,去重)
db.users.updateOne(
{ name: "张三" },
{ $addToSet: { hobbies: "编程" } } // 如果已存在则不添加
)
// $addToSet添加多个元素
db.users.updateOne(
{ name: "张三" },
{ $addToSet: { hobbies: { $each: ["编程", "阅读"] } } }
)
// $pop - 删除数组第一个或最后一个元素
db.users.updateOne(
{ name: "张三" },
{ $pop: { hobbies: 1 } } // 1删除最后一个,-1删除第一个
)
// $pull - 删除匹配的元素
db.users.updateOne(
{ name: "张三" },
{ $pull: { hobbies: "游泳" } } // 删除值为"游泳"的元素
)
// $pull按条件删除
db.users.updateOne(
{ name: "张三" },
{ $pull: { scores: { $lt: 60 } } } // 删除小于60的分数
)
// $pullAll - 删除多个元素
db.users.updateOne(
{ name: "张三" },
{ $pullAll: { hobbies: ["游泳", "跑步"] } }
)
// 更新数组中特定位置的元素
db.users.updateOne(
{ name: "张三" },
{ $set: { "hobbies.0": "新爱好" } } // 更新第一个元素
)
// 更新数组中匹配条件的元素
db.users.updateOne(
{ name: "张三", "grades.subject": "数学" },
{ $set: { "grades.$.score": 95 } } // $表示匹配的元素位置
)删除文档
deleteOne - 删除单个文档
javascript
// 删除单个文档
db.users.deleteOne({ name: "张三" })
// 输出:{ acknowledged: true, deletedCount: 1 }
// 删除第一个匹配的文档
db.users.deleteOne({ age: { $gt: 30 } })
// 删除并返回被删除的文档
db.users.findOneAndDelete({ name: "张三" })
// 删除并返回,按排序
db.users.findOneAndDelete(
{ age: { $gt: 20 } },
{ sort: { age: -1 } } // 删除年龄最大的
)deleteMany - 批量删除文档
javascript
// 批量删除文档
db.users.deleteMany({ city: "北京" })
// 输出:{ acknowledged: true, deletedCount: 100 }
// 删除所有文档
db.users.deleteMany({})
// 输出:{ acknowledged: true, deletedCount: 1000 }
// 按条件批量删除
db.users.deleteMany({
createdAt: { $lt: new Date("2023-01-01") }
})remove - 兼容方法
javascript
// remove方法(已弃用,但仍可用)
// 删除所有匹配的文档
db.users.remove({ name: "张三" })
// 只删除一个
db.users.remove({ name: "张三" }, { justOne: true })删除操作最佳实践
javascript
// 删除操作最佳实践
// 1. 删除前先查询确认
var toDelete = db.users.find({ status: "inactive" }).count()
print("将删除 " + toDelete + " 条文档")
// 确认后再删除
db.users.deleteMany({ status: "inactive" })
// 2. 大批量删除时分批进行
var batchSize = 1000;
var totalDeleted = 0;
while (true) {
var result = db.users.deleteMany(
{ createdAt: { $lt: new Date("2023-01-01") } },
{ limit: batchSize }
);
totalDeleted += result.deletedCount;
print("已删除 " + totalDeleted + " 条文档");
if (result.deletedCount < batchSize) {
break; // 删除完成
}
}
// 3. 使用事务确保数据一致性
// (在事务章节详细介绍)批量写入操作
bulkWrite - 批量写入
javascript
// bulkWrite支持多种操作混合批量执行
db.users.bulkWrite([
// 插入操作
{ insertOne: { document: { name: "用户1", age: 20 } } },
{ insertOne: { document: { name: "用户2", age: 25 } } },
// 更新操作
{ updateOne: {
filter: { name: "张三" },
update: { $set: { age: 26 } }
}},
// 批量更新
{ updateMany: {
filter: { city: "北京" },
update: { $set: { region: "华北" } }
}},
// 删除操作
{ deleteOne: { filter: { name: "删除用户" } } },
// 批量删除
{ deleteMany: { filter: { status: "deleted" } } },
// 替换操作
{ replaceOne: {
filter: { name: "李四" },
replacement: { name: "李四", age: 30, city: "上海" }
}}
], { ordered: false }) // ordered: false表示遇到错误继续执行
// 输出示例:
// {
// acknowledged: true,
// insertedCount: 2,
// insertedIds: { '0': ObjectId("..."), '1': ObjectId("...") },
// matchedCount: 3,
// modifiedCount: 3,
// deletedCount: 2
// }本章小结
本章详细介绍了MongoDB文档的CRUD操作:
- 文档结构:理解文档的基本概念和支持的数据类型
- 插入文档:掌握insertOne、insertMany的使用方法
- 查询文档:学会使用find、findOne和各种查询操作符
- 更新文档:掌握updateOne、updateMany和各种更新操作符
- 删除文档:学会使用deleteOne、deleteMany删除文档
- 数组操作:掌握数组的添加、删除、更新操作
- 批量操作:学会使用bulkWrite进行批量写入
下一章,我们将学习查询进阶,了解更复杂的查询技巧。
