1. 概述

$push 是MongoDB中的一个更新运算符,用于在数组中添加值。相比之下,$set 运算符用于更新文档中现有字段的值。

在这篇简短教程中,我们将介绍如何在一个更新查询中同时使用 $push$set 操作。

2. 数据库初始化

在进行多字段更新操作(/mongodb-update-multiple-fields)之前,我们首先需要设置一个名为 baeldung 的数据库和一个样本集合 marks

use baeldung;
db.createCollection(marks);

使用MongoDB的 insertMany 方法向 marks 集合中插入一些文档:

db.marks.insertMany([
    {
        "studentId": 1023,
        "studentName":"James Broad",
        "joiningYear":"2018",
        "totalMarks":100,
        "subjectDetails":[
            {
                "subjectId":123,
                "subjectName":"Operating Systems Concepts",
                "marks":40
            },
            {
                "subjectId":124,
                "subjectName":"Numerical Analysis",
                "marks":60
            }
        ]
    },
    {
        "studentId": 1024,
        "studentName":"Chris Overton",
        "joiningYear":"2018",
        "totalMarks":110,
        "subjectDetails":[
            {
                "subjectId":123,
                "subjectName":"Operating Systems Concepts",
                "marks":50
            },
            {
                "subjectId":124,
                "subjectName":"Numerical Analysis",
                "marks":60
            }
        ]
    }
]);

成功插入后,上述查询将返回以下响应:

{
    "acknowledged" : true,
    "insertedIds" : [
        ObjectId("622300cc85e943405d04b567"),
        ObjectId("622300cc85e943405d04b568")
    ]
}

至此,我们已成功将几个示例文档插入到 marks 集合中。

3. 理解问题

为了理解问题,让我们先看看刚刚插入的文档。它包含了学生信息以及他们在不同科目中的成绩。totalMarks 是不同科目得分的总和。

假设我们希望在 subjectDetails 数组中添加一个新的科目。为了保持数据一致性,我们也需要更新 totalMarks 字段。

在MongoDB中,首先使用 $push 运算符将新科目添加到数组中,然后使用 $set 运算符设置 totalMarks 字段为特定值。

这些操作可以分别使用 $push$set 运算符单独完成。但我们可以编写MongoDB查询来同时执行这两个操作。

4. 使用MongoDB命令行查询

在MongoDB中,我们可以使用不同的更新运算符来更新文档的多个字段。这里,我们将一起在 updateOne 查询中使用 $push$set 运算符。

让我们查看包含两个运算符的示例查询:

db.marks.updateOne(
    {
        "studentId": 1023
    },
    {
        $set: {
            totalMarks: 170
        },
        $push: {
            "subjectDetails":{
                "subjectId": 126,
                "subjectName": "Java Programming",
                "marks": 70
            }
        }
    }
);

在这个查询中,我们基于 studentId 过滤文档。一旦获取到过滤后的文档,我们就可以使用 $set 运算符更新 totalMarks。此外,我们还使用 $push 运算符将新的科目数据插入到 subjectDetails 数组中。

因此,上述查询将返回以下输出:

{
    "acknowledged":true,
    "matchedCount":1,
    "modifiedCount":1
}

在这里,matchedCount 包含匹配过滤条件的文档数量,而 modifiedCount 包含被修改的文档数量。

5. Java驱动代码

到目前为止,我们讨论了在MongoDB命令行查询中一起使用 $push$set 运算符的方法。接下来,我们将学习如何使用Java驱动程序实现相同的操作。

在继续之前,我们先连接到数据库和所需的集合:

MongoClient mongoClient = new MongoClient(new MongoClientURI("localhost", 27017);
MongoDatabase database = mongoClient.getDatabase("baeldung");
MongoCollection<Document> collection = database.getCollection("marks");

这里,我们连接到本地主机默认端口27017运行的MongoDB。

现在让我们看看Java驱动程序代码:

Document subjectData = new Document()
  .append("subjectId", 126)
  .append("subjectName", "Java Programming")
  .append("marks", 70); 
UpdateResult updateQueryResult = collection.updateOne(Filters.eq("studentId", 1023), 
  Updates.combine(Updates.set("totalMarks", 170), 
  Updates.push("subjectDetails", subjectData)));

在这个代码片段中,我们使用了 updateOne 方法,根据 studentId 1023应用过滤器来更新单个文档。然后,我们使用 Updates.combine 在一次调用中执行多个操作。totalMarks 字段将被更新为170,而新的文档 subjectData 将被推送到 “subjectDetails” 数组字段中。

6. 总结

在本文中,我们理解了在一个MongoDB查询中同时应用多个操作的用例,并通过MongoDB命令行查询和Java驱动程序代码进行了实践。

如往常一样,所有示例的源代码和代码片段可在GitHub上找到。