对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
See how MongoDB 9.0 delivers up to 2x higher throughput.
MongoDB Branding Shape
Register now >
Docs 菜单

使用 POJO 建模数据

在本指南中,您可以学习如何使用 Java 反应式流驱动程序来存储和检索由普通旧 Java 对象(或 POJO)建模的数据。POJO 通常用于数据封装,这是将业务逻辑与数据表示分开的做法。

提示

要学习有关 POJO 的更多信息,请参阅普通旧 Java 对象维基百科条目。

本指南介绍如何执行以下任务:

  • 配置驱动程序,对 POJO 进行序列化和反序列化

  • 对使用 POJO 建模的数据进行 CRUD 操作

重要

本指南使用自定义Subscriber实现,如《自定义订阅服务器实现示例》指南中所述。

本指南中的示例使用 Person 和 Address POJO 类为名为 people 的示例集合中的文档建模。

Person 类存储人员的姓名、年龄和地址。此类具有以下定义:

import org.bson.types.ObjectId;
public final class Person {
private ObjectId id;
private String name;
private int age;
private Address address;
public Person() {}
public Person(final String name, final int age, final Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public ObjectId getId() { return id; }
public void setId(final ObjectId id) { this.id = id; }
public String getName() { return name; }
public void setName(final String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(final int age) { this.age = age; }
public Address getAddress() { return address; }
public void setAddress(final Address address) { this.address = address; }
@Override
public String toString() {
return "Person{"
+ "id='" + id + "'"
+ ", name='" + name + "'"
+ ", age=" + age
+ ", address=" + address
+ "}";
}
}

Address 类存储街道、城市和 ZIP 编码。此类具有以下定义:

public final class Address {
private String street;
private String city;
private String zip;
public Address() {}
public Address(final String street, final String city, final String zip) {
this.street = street;
this.city = city;
this.zip = zip;
}
public String getStreet() { return street; }
public void setStreet(final String street) { this.street = street; }
public String getCity() { return city; }
public void setCity(final String city) { this.city = city; }
public String getZip() { return zip; }
public void setZip(final String zip) { this.zip = zip; }
@Override
public String toString() {
return "Address{"
+ "street='" + street + "'"
+ ", city='" + city + "'"
+ ", zip='" + zip + "'"
+ "}";
}
}

定义 POJO 类时,请确保满足以下要求:

  • POJO 类不能实现接口或继承框架中的类。

  • 放入您要存储和检索数据的所有字段,并确保它们没有标记为 static 或 transient。

  • 如果您按照 JavaBean 命名规范包含公共 getter 或 setter 方法,则驱动程序将在序列化或反序列化数据时调用这些方法。如果您省略公共字段的 getter 或 setter 方法,则驱动程序将直接访问或赋值这些字段。

在将 POJO 与 Java Reactive Streams 驱动程序一起使用之前,必须通过创建自定义 CodecRegistry 将其配置为序列化和反序列化 POJO。以下步骤展示如何创建 CodecRegistry 并将其应用于客户端、数据库或集合。

1

以下代码使用 PojoCodecProvider.Builder 类的 automatic(true) 设置将 POJO 编解码器自动应用于任何类及其属性:

CodecProvider pojoCodecProvider = PojoCodecProvider.builder().automatic(true).build();
2

创建一个 CodecRegistry,将默认编解码注册表与 PojoCodecProvider 结合,如以下代码所示:

CodecRegistry pojoCodecRegistry = fromRegistries(
getDefaultCodecRegistry(),
fromProviders(pojoCodecProvider)
);

注意

注册表按顺序检查,直到有一个返回所请求类的编解码器。在列表中首先包含默认编解码器注册表,并将 PojoCodecProvider 放在最后,因为它可以为几乎所有类提供编解码器。

3

将 MongoClient、MongoDatabase 或 MongoCollection 实例配置为使用自定义 CodecRegistry。您可以通过以下方式之一设置编解码器注册表:

  1. 在 MongoClient 上设置 CodecRegistry:

    MongoClientSettings settings = MongoClientSettings.builder()
    .codecRegistry(pojoCodecRegistry)
    .build();
  2. 在 MongoDatabase 上设置 CodecRegistry:

    MongoDatabase database = mongoClient.getDatabase("mydb").withCodecRegistry(pojoCodecRegistry);
  3. 在 MongoCollection 上设置 CodecRegistry:

    MongoCollection<org.bson.Document> rawCollection = database.getCollection("people").withCodecRegistry(pojoCodecRegistry);
4

将 POJO 类作为文档类参数传递给 getCollection(),并将其指定为 MongoCollection 实例的类型参数,如以下代码所示:

MongoCollection<Person> collection = database.getCollection("people", Person.class);

将驱动程序配置为使用 Person POJO 后,您可以对 POJO 建模的数据执行 CRUD 操作。

编解码器注册表会自动为未知类创建 POJO Codec ,使您可以开箱即用 POJO,无需额外配置。

要将单个 Person 插入到集合中,调用 insertOne() 方法并订阅结果。以下示例将名为 ada 的 Person 实例插入到 people 集合中:

Person ada = new Person("Ada Byron", 20, new Address("St James Square", "London", "W1"));
collection.insertOne(ada).subscribe(new OperationSubscriber<InsertOneResult>());

要插入多个 Person 实例,调用 insertMany() 方法并传递实例列表,如以下示例所示:

List<Person> people = asList(
new Person("Charles Babbage", 45, new Address("5 Devonshire Street", "London", "W11")),
new Person("Alan Turing", 28, new Address("Bletchley Hall", "Bletchley Park", "MK12")),
new Person("Timothy Berners-Lee", 61, new Address("Colehill", "Wimborne", null))
);
collection.insertMany(people).subscribe(new OperationSubscriber<InsertManyResult>());

要查询集合,请使用 find() 方法。您可以将过滤器对象传递给 find() 方法,以检索符合特定条件的文档。驱动程序提供 Filters 个辅助工具方法,您可以使用这些方法创建过滤器对象。

重要

查询 POJO 时,必须查询文档字段名称,而不是 POJO 属性名称。默认情况下,它们是相同的,但可以更改驱动程序映射 POJO 属性名称的方式。

要检索符合过滤器的第一个 Person 实例,请在 find() 操作的结果上调用 first() 方法。

以下示例检索具有 address.city 字段值 "Wimborne" 的第一个 Person 实例:

collection.find(eq("address.city", "Wimborne"))
.first()
.subscribe(new PrintToStringSubscriber<>());

要检索符合过滤器的所有 Person 实例,请调用 find() 方法并订阅结果。

以下示例检索每个具有大于 30 的 age 字段值的 Person 实例:

collection.find(gt("age", 30)).subscribe(new PrintToStringSubscriber<>());

要更新集合中的文档,请使用 updateOne() 和 updateMany() 方法。将以下参数传递给这些方法:

  • 指定要更新的文档的过滤器对象。

  • 更新指定修改的文档。要查看可用操作符的列表,请参阅 MongoDB Server 手册中的更新操作符。

更新方法返回 UpdateResult 类型,其中提供有关操作的信息,包括修改的文档数量。

要更新与筛选器匹配的单个 Person 实例,请使用 updateOne() 方法。

以下示例通过将 age 字段值设置为 23,并将 name 字段值设置为 "Ada Lovelace",来更新命名为 "Ada Byron" 的 Person:

collection.updateOne(
eq("name", "Ada Byron"),
combine(set("age", 23), set("name", "Ada Lovelace"))
).subscribe(new OperationSubscriber<>());

要更新与筛选器匹配的所有Person实例,请使用updateMany()方法。

以下示例将所有具有非空 zip 值的 Person 实例的 zip 字段值设置为 null:

collection.updateMany(not(eq("zip", null)), set("zip", null))
.subscribe(new OperationSubscriber<>());

要完全替换现有的 Person 实例,请使用 replaceOne() 方法。

以下示例将具有 name 字段值 "Ada Lovelace" 的 Person 实例替换为 ada 变量引用的 Person:

collection.replaceOne(eq("name", "Ada Lovelace"), ada)
.subscribe(new OperationSubscriber<>());

要从集合中删除文档,请使用 deleteOne() 和 deleteMany() 方法。传递过滤器对象以匹配要删除的文档。

删除方法返回DeleteResult类型,其中提供有关操作的信息,包括删除的文档数。

要删除与过滤器匹配的单个Person ,请使用deleteOne()方法。

以下示例删除一个字段值为Person address.city的"Wimborne" 实例:

collection.deleteOne(eq("address.city", "Wimborne"))
.subscribe(new OperationSubscriber<>());

要删除与过滤器匹配的所有 Person 实例,请使用 deleteMany() 方法。

Personaddress.city以下示例删除字段值为 的所有"London" 实例:

collection.deleteMany(eq("address.city", "London"))
.subscribe(new OperationSubscriber<>());

要了解本指南中提到的 CRUD 操作的更多信息,请参阅CRUD 操作部分。

要了解有关本指南中提到的方法和类的更多信息,请参阅以下 API 文档: