For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.
Docs Menu

Use POJOs to Model Your Data

In this guide, you can learn how to use the Java Reactive Streams driver to store and retrieve data modeled by plain old Java objects, or POJOs. POJOs are often used for data encapsulation, which is the practice of separating business logic from data representation.

Tip

To learn more about POJOs, see the Plain old Java object Wikipedia entry.

This guide shows how to perform the following tasks:

  • Configure the driver to serialize and deserialize POJOs

  • Perform CRUD operations by using data modeled by POJOs

Important

This guide uses custom Subscriber implementations, which are described in the Sample Custom Subscriber Implementations guide.

The examples in this guide use the Person and Address POJO classes to model documents in a sample collection named people.

The Person class stores a person's name, age, and address. This class has the following definition:

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
+ "}";
}
}

The Address class stores a street, city, and ZIP code. This class has the following definition:

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 + "'"
+ "}";
}
}

When you define a POJO class, ensure that you meet the following requirements:

  • The POJO class cannot implement interfaces or extend classes from a framework.

  • Include all fields for which you want to store and retrieve data, and ensure that they are not marked as static or transient.

  • If you include public getter or setter methods following the JavaBean naming conventions, the driver calls them when serializing or deserializing data. If you omit getter or setter methods for a public field, the driver accesses or assigns them directly.

Before you can use a POJO with the Java Reactive Streams driver, you must configure it to serialize and deserialize POJOs by creating a custom CodecRegistry. The following steps show how to create the CodecRegistry and apply it to a client, database, or collection.

1

The following code uses the automatic(true) setting of the PojoCodecProvider.Builder class to automatically apply the POJO codec to any class and its properties:

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

Create a CodecRegistry that combines the default codec registry with the PojoCodecProvider, as shown in the following code:

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

Note

Registries are checked in order until one returns a codec for the requested class. Include the default codec registry first in the list, and include the PojoCodecProvider last because it can provide a codec for almost any class.

3

Configure a MongoClient, MongoDatabase, or MongoCollection instance to use the custom CodecRegistry. You can set the codec registry in one of the following ways:

  1. Set the CodecRegistry on a MongoClient:

    MongoClientSettings settings = MongoClientSettings.builder()
    .codecRegistry(pojoCodecRegistry)
    .build();
  2. Set the CodecRegistry on a MongoDatabase:

    MongoDatabase database = mongoClient.getDatabase("mydb").withCodecRegistry(pojoCodecRegistry);
  3. Set the CodecRegistry on a MongoCollection:

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

Pass your POJO class to getCollection() as the document class parameter and specify it as the type argument of your MongoCollection instance, as shown in the following code:

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

After you configure the driver to use the Person POJO, you can perform CRUD operations on data modeled by the POJO.

The codec registry automatically creates a POJO Codec for unknown classes, allowing you to use POJOs out of the box without extra configuration.

To insert a single Person into the collection, call the insertOne() method and subscribe to the result. The following example inserts a Person instance named ada into the people collection:

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

To insert multiple Person instances, call the insertMany() method and pass a list of instances, as shown in the following example:

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

To query the collection, use the find() method. You can pass a filter object to the find() method to retrieve documents that match certain conditions. The driver provides Filters helper methods that you can use to create filter objects.

Important

When querying POJOs, you must query against the document field name and not the POJO property name. They are the same by default, but it is possible to change how the driver maps POJO property names.

To retrieve the first Person instance that matches a filter, call the first() method on the result of a find() operation.

The following example retrieves the first Person instance that has an address.city field value of "Wimborne":

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'}}

To retrieve all Person instances that match a filter, call the find() method and subscribe to the results.

The following example retrieves every Person instance that has an age field value greater than 30:

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'}}

To update documents in a collection, use the updateOne() and updateMany() methods. Pass the following parameters to these methods:

  • Filter object that specifies the document or documents to update.

  • Update document that specifies the modifications. To view a list of available operators, see Update Operators in the MongoDB Server manual.

The update methods return an UpdateResult type that provides information about the operation, including the number of documents modified.

To update a single Person instance that matches a filter, use the updateOne() method.

The following example updates the Person named "Ada Byron" by setting the age field value to 23 and name field value to "Ada Lovelace":

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

To update all Person instances that match a filter, use the updateMany() method.

The following example sets the zip field value to null for all Person instances that have a non-null zip value:

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

To replace an existing Person instance entirely, use the replaceOne() method.

The following example replaces the Person instance that has a name field value of "Ada Lovelace" with the Person referenced by the ada variable:

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

To delete documents from a collection, use the deleteOne() and deleteMany() methods. Pass a filter object to match the document or documents to delete.

The delete methods return a DeleteResult type that provides information about the operation, including the number of documents deleted.

To delete a single Person that matches a filter, use the deleteOne() method.

The following example deletes one Person instance that has an address.city field value of "Wimborne":

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

To delete all Person instances that match a filter, use the deleteMany() method.

The following example deletes all Person instances that have an address.city field value of "London":

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

To learn more about the CRUD operations mentioned in this guide, see the CRUD Operations section.

To learn more about the methods and classes mentioned in this guide, see the following API documentation: