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

使用 POJO 对数据进行建模

在本指南中,您可以学习;了解如何使用Java Reactive Streams驾驶员来存储和检索由普通旧Java对象 (POJO) 建模的数据。 POJO 通常用于数据封装,这是将业务逻辑与数据表示分离的做法。

提示

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

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

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

  • 使用 POJO 建模的数据执行增删改查操作

重要

本指南使用自定义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 类存储街道、城市和邮政编码。该类具有以下定义:

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

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

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 建模的数据执行增删改查操作。

编解码器注册表会自动为未知类创建 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() 方法并订阅结果。

以下示例检索 age字段值大于 30 的每个 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()方法。

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

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

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

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

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

要学习;了解有关本指南中提及的增删改查操作的更多信息,请参阅增删改查操作部分。

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