对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

使用 POJO 建模数据

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

提示

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

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

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

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

重要

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

本指南中的示例使用 PersonAddress 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 类不能实现接口或继承框架中的类。

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

  • 如果您按照 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

MongoClientMongoDatabaseMongoCollection 实例配置为使用自定义 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() 方法并订阅结果。以下示例将名为 adaPerson 实例插入到 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{id='...', name='Timothy Berners-Lee', age=61, address=Address{street='Colehill', city='Wimborne', zip='null'}}

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

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

collection.find(gt("age", 30)).subscribe(new PrintToStringSubscriber<>());
Person{id='...', name='Charles Babbage', age=45, address=Address{street='5 Devonshire Street', city='London', zip='W11'}}
Person{id='...', name='Timothy Berners-Lee', age=61, address=Address{street='Colehill', city='Wimborne', zip='null'}}

要更新集合中的文档,请使用 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 文档: