1. 概述

MongoDB 是一个跨平台、文档导向的开源NoSQL数据库,用C++编写。此外,MongoDB还提供了高性能、高可用性和自动扩展功能。

为了在MongoDB中更新文档,我们可以使用不同的方法,如updateOnefindOneAndUpdate等。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
}

如果我们设置returnNewDocumenttrue,操作将返回替换后的文档:

{
    "student_id":8764,
    "student_name":"Paul Starc",
    "address":"Hostel 2",
    "age":18,
    "roll_no":199406
}

现在,让我们使用findOneAndReplace方法来在返回的文档中投影student_idage字段:

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
        }
    }
);

查询的输出将只包含旧文档的studentIdaddress

{
    "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_idaddress字段。

8. 结论

在这篇文章中,我们探讨了在MongoDB中更新文档的各种方法。首先我们了解了MongoDB shell查询,然后讨论了相应的Java驱动代码。

所有这些示例和代码片段的实现可以在GitHub上找到。


« 上一篇: OAuth2RestTemplate介绍
» 下一篇: Java Weekly, 第428期