1. 概述
MongoDB 是一个跨平台、文档导向的开源NoSQL数据库,用C++编写。此外,MongoDB还提供了高性能、高可用性和自动扩展功能。
为了在MongoDB中更新文档,我们可以使用不同的方法,如updateOne
、findOneAndUpdate
等。MongoDB还为更新方法提供了各种操作符。
在这个教程中,我们将讨论在MongoDB中执行更新操作的不同方法。对于每种方法,我们首先会讨论MongoDB shell查询,然后是其在Java中的实现。
2. 数据库设置
在进行更新查询之前,我们先创建一个数据库baeldung
和一个示例集合student:
use baeldung;
db.createCollection(student);
举个例子,我们使用insertMany
查询向student
集合添加一些文档:
db.student.insertMany([
{
"student_id": 8764,
"student_name": "Paul Starc",
"address": "Hostel 1",
"age": 16,
"roll_no":199406
},
{
"student_id": 8765,
"student_name": "Andrew Boult",
"address": "Hostel 2",
"age": 18,
"roll_no":199408
}
]);
插入成功后,我们会得到一个包含acknowledged:true
的JSON:
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("621b078485e943405d04b557"),
ObjectId("621b078485e943405d04b558")
]
}
现在,让我们深入探讨在MongoDB中更新文档的各种方式。
3. 使用updateOne
方法
MongoDB中的更新操作可以添加新字段、删除字段或更新现有字段。updateOne
方法根据应用的查询过滤器在一个集合中更新单个文档。它首先找到匹配过滤器的文档,然后更新指定的字段。
此外,我们还可以使用不同的操作符,如$set
、$unset
、$inc
等与更新方法一起使用。
来看一个查询示例,用于更新集合中的单个文档:
db.student.updateOne(
{
"student_name" : "Paul Starc"
},
{
$set: {
"address" : "Hostel 2"
}
}
);
输出将类似于以下内容:
{
"acknowledged":true,
"matchedCount":1,
"modifiedCount":1
}
现在,我们来看看上述updateOne
查询的Java驱动代码:
UpdateResult updateResult = collection.updateOne(Filters.eq("student_name", "Paul Starc"),
Updates.set("address", "Hostel 2"));
这里,我们首先使用student_name
字段来过滤文档,然后更新student_name
为"Paul Starc"的文档地址。
4. 使用updateMany
方法
updateMany
方法通过给定的过滤器更新MongoDB集合中的所有文档。使用updateMany
的一个好处是可以更新多个文档,而不会丢失旧文档的字段。
让我们看看使用updateMany
方法的MongoDB shell查询:
db.student.updateMany(
{
age: {
$lt: 20
}
},
{
$set:{
"Review" : true
}
}
);
此命令将返回如下输出:
{
"acknowledged":true,
"matchedCount":2,
"modifiedCount":2
}
其中,matchedCount
包含匹配文档的数量,modifiedCount
包含被修改的文档数量。
现在,让我们看看使用updateMany
方法的Java驱动代码:
UpdateResult updateResult = collection.updateMany(Filters.lt("age", 20), Updates.set("Review", true));
在这里,所有年龄小于20的文档都会被过滤,并将Review
字段设置为true
。
5. 使用replaceOne
方法
MongoDB的replaceOne
方法替换整个文档。**replaceOne
的一个缺点是,所有旧字段将被新字段替换,旧字段也会丢失:**
db.student.replaceOne(
{
"student_id": 8764
},
{
"student_id": 8764,
"student_name": "Paul Starc",
"address": "Hostel 2",
"age": 18,
"roll_no":199406
}
);
在这种情况下,我们将得到以下输出:
{
"acknowledged":true,
"matchedCount":1,
"modifiedCount":1
}
如果未找到匹配项,操作将返回matchedCount
为0:
{
"acknowledged":true,
"matchedCount":0,
"modifiedCount":0
}
现在,我们用replaceOne
方法的Java驱动代码来编写相应代码:
Document replaceDocument = new Document();
replaceDocument
.append("student_id", 8764)
.append("student_name", "Paul Starc")
.append("address", "Hostel 2")
.append("age",18)
.append("roll_no", 199406);
UpdateResult updateResult = collection.replaceOne(Filters.eq("student_id", 8764), replaceDocument);
在上述代码中,我们创建了一个文档,用于替换旧文档。具有student_id
为8764的文档将被新创建的文档替换。
6. 使用findOneAndReplace
方法
MongoDB提供的高级更新方法之一是findOneAndReplace
,它根据给定的选择标准替换第一个匹配的文档。默认情况下,此方法返回原始文档。我们可以根据需要使用findOneAndReplace
的不同选项来对文档进行排序和投影。
简而言之,findOneAndReplace
根据应用的过滤器替换集合中的第一个匹配文档:
db.student.findOneAndReplace(
{
"student_id" : {
$eq : 8764
}
},
{
"student_id" : 8764,
"student_name" : "Paul Starc",
"address": "Hostel 2",
"age": 18,
"roll_no":199406
},
{
returnNewDocument: false
}
);
这个查询将返回以下文档:
{
"student_id":8764,
"student_name":"Paul Starc",
"address":"Hostel 1",
"age":16,
"roll_no":199406
}
如果我们设置returnNewDocument
为true
,操作将返回替换后的文档:
{
"student_id":8764,
"student_name":"Paul Starc",
"address":"Hostel 2",
"age":18,
"roll_no":199406
}
现在,让我们使用findOneAndReplace
方法来在返回的文档中投影student_id
和age
字段:
db.student.findOneAndReplace(
{
"student_id" : {
$eq : 8764
}
},
{
"student_id" : 8764,
"student_name" : "Paul Starc",
"address": "Hostel 2",
"age": 18,
"roll_no":199406
},
{
projection: {
"_id" : 0,
"student_id":1,
"age" : 1
}
}
);
上述查询的输出将只包含投影的字段:
{
"student_id":"8764",
"age":16
}
上述查询的Java驱动代码,包括findOneAndReplace
的各种选项:
Document replaceDocument = new Document();
replaceDocument
.append("student_id", 8764)
.append("student_name", "Paul Starc")
.append("address", "Hostel 2")
.append("age", 18)
.append("roll_no", 199406);
Document sort = new Document("roll_no", 1);
Document projection = new Document("_id", 0).append("student_id", 1).append("address", 1);
Document resultDocument = collection.findOneAndReplace(
Filters.eq("student_id", 8764),
replaceDocument,
new FindOneAndReplaceOptions().upsert(true).sort(sort).projection(projection).returnDocument(ReturnDocument.AFTER));
在这段代码中,findOneAndReplace
方法首先根据roll_no
字段升序排序文档,然后新创建的文档替换student_id
为"8764"的文档。
7. 使用findOneAndUpdate
方法
findOneAndUpdate
方法更新集合中的第一个匹配文档。如果有多于一个文档匹配选择标准,则仅更新第一个匹配的文档。当我们更新文档时,_id
字段的值保持不变:
db.student.findOneAndUpdate(
{
"student_id" : 8764
},
{
$inc : {
"roll_no" : 5
}
},
{
sort: {
"roll_no" : 1
},
projection: {
"_id" : 0,
"student_id":1,
"address" : 1
}
}
);
查询的输出将只包含旧文档的studentId
和address
:
{
"student_id":8764,
"address":"Hostel 1"
}
上述查询的Java驱动代码(使用findOneAndUpdate
的不同选项)如下:
Document sort = new Document("roll_no", 1);
Document projection = new Document("_id", 0).append("student_id", 1).append("address", 1);
Document resultDocument = collection.findOneAndUpdate(
Filters.eq("student_id", 8764),
Updates.inc("roll_no", 5),
new FindOneAndUpdateOptions().sort(sort).projection(projection).returnDocument(ReturnDocument.BEFORE));
在这个例子中,findOneAndUpdate
方法首先根据roll_no
字段升序排序文档。上述查询将roll_no
递增5,然后返回student_id
和address
字段。
8. 结论
在这篇文章中,我们探讨了在MongoDB中更新文档的各种方法。首先我们了解了MongoDB shell查询,然后讨论了相应的Java驱动代码。
所有这些示例和代码片段的实现可以在GitHub上找到。