Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

Join us at AWS re:Invent 2024! Learn how to use MongoDB for AI use cases.
MongoDB Developer
Java
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
Javachevron-right

Java - Mapping POJOs

Maxime Beugnet5 min read • Published Feb 01, 2022 • Updated Mar 01, 2024
MongoDBJava
Facebook Icontwitter iconlinkedin icon
Rate this quickstart
star-empty
star-empty
star-empty
star-empty
star-empty

Updates

The MongoDB Java quickstart repository is available on GitHub.

February 28th, 2024

  • Update to Java 21
  • Update Java Driver to 5.0.0
  • Update logback-classic to 1.2.13

November 14th, 2023

  • Update to Java 17
  • Update Java Driver to 4.11.1
  • Update mongodb-crypt to 1.8.0

March 25th, 2021

  • Update Java Driver to 4.2.2.
  • Added Client Side Field Level Encryption example.

October 21st, 2020

  • Update Java Driver to 4.1.1.
  • The Java Driver logging is now enabled via the popular SLF4J API, so I added logback in the pom.xml and a configuration file logback.xml.

Introduction

Java badge
Java is an object-oriented programming language and MongoDB stores documents, which look a lot like objects. Indeed, this is not a coincidence because that's the core idea behind the MongoDB database.
In this blog post, as promised in the first blog post of this series, I will show you how to automatically map MongoDB documents to Plain Old Java Objects (POJOs) using only the MongoDB driver.

Getting Set Up

I will use the same repository as usual in this series. If you don't have a copy of it yet, you can clone it or just update it if you already have it:
1git clone https://github.com/mongodb-developer/java-quick-start
If you haven't yet set up your free cluster on MongoDB Atlas, now is a great time to do so. You have all the instructions in this blog post.

The Grades Collection

If you followed this series, you know that we have been working with the grades collection in the sample_training database. You can import it easily by loading the sample dataset in MongoDB Atlas.
Here is what a MongoDB document looks like in extended JSON format. I'm using the extended JSON because it's easier to identify the field types and we will need them to build the POJOs.
1{
2 "_id": {
3 "$oid": "56d5f7eb604eb380b0d8d8ce"
4 },
5 "student_id": {
6 "$numberDouble": "0"
7 },
8 "scores": [{
9 "type": "exam",
10 "score": {
11 "$numberDouble": "78.40446309504266"
12 }
13 }, {
14 "type": "quiz",
15 "score": {
16 "$numberDouble": "73.36224783231339"
17 }
18 }, {
19 "type": "homework",
20 "score": {
21 "$numberDouble": "46.980982486720535"
22 }
23 }, {
24 "type": "homework",
25 "score": {
26 "$numberDouble": "76.67556138656222"
27 }
28 }],
29 "class_id": {
30 "$numberDouble": "339"
31 }
32}

POJOs

The first thing we need is a representation of this document in Java. For each document or subdocument, I need a corresponding POJO class.
As you can see in the document above, I have the main document itself and I have an array of subdocuments in the scores field. Thus, we will need 2 POJOs to represent this document in Java:
  • One for the grade,
  • One for the scores.
In the package com.mongodb.quickstart.models, I created two new POJOs: Grade.java and Score.java.
1package com.mongodb.quickstart.models;
2
3// imports
4
5public class Grade {
6
7 private ObjectId id;
8 @BsonProperty(value = "student_id")
9 private Double studentId;
10 @BsonProperty(value = "class_id")
11 private Double classId;
12 private List<Score> scores;
13
14 // getters and setters with builder pattern
15 // toString()
16 // equals()
17 // hashCode()
18}
In the Grade class above, I'm using @BsonProperty to avoid violating Java naming conventions for variables, getters, and setters. This allows me to indicate to the mapper that I want the "student_id" field in JSON to be mapped to the "studentId" field in Java.
1package com.mongodb.quickstart.models;
2
3import java.util.Objects;
4
5public class Score {
6
7 private String type;
8 private Double score;
9
10 // getters and setters with builder pattern
11 // toString()
12 // equals()
13 // hashCode()
14}
As you can see, we took care of matching the Java types with the JSON value types to follow the same data model. You can read more about types and documents in the documentation.

Mapping POJOs

Now that we have everything we need, we can start the MongoDB driver code.
I created a new class MappingPOJO in the com.mongodb.quickstart package and here are the key lines of code:
  • I need a ConnectionString instance instead of the usual String I have used so far in this series. I'm still retrieving my MongoDB Atlas URI from the system properties. See my starting and setup blog post if you need a reminder.
1ConnectionString connectionString = new ConnectionString(System.getProperty("mongodb.uri"));
  • I need to configure the CodecRegistry to include a codec to handle the translation to and from BSON for our POJOs.
1CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
  • And I need to add the default codec registry, which contains all the default codecs. They can handle all the major types in Java-like Boolean, Double, String, BigDecimal, etc.
1CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
2 pojoCodecRegistry);
  • I can now wrap all my settings together using MongoClientSettings.
1MongoClientSettings clientSettings = MongoClientSettings.builder()
2 .applyConnectionString(connectionString)
3 .codecRegistry(codecRegistry)
4 .build();
  • I can finally initialise my connection with MongoDB.
1try (MongoClient mongoClient = MongoClients.create(clientSettings)) {
2 MongoDatabase db = mongoClient.getDatabase("sample_training");
3 MongoCollection<Grade> grades = db.getCollection("grades", Grade.class);
4 [...]
5}
As you can see in this last line of Java, all the magic is happening here. The MongoCollection<Grade> I'm retrieving is typed by Grade and not by Document as usual.
In the previous blog posts in this series, I showed you how to use CRUD operations by manipulating MongoCollection<Document>. Let's review all the CRUD operations using POJOs now.
  • Here is an insert (create).
1Grade newGrade = new Grade().setStudent_id(10003d)
2 .setClass_id(10d)
3 .setScores(List.of(new Score().setType("homework").setScore(50d)));
4grades.insertOne(newGrade);
  • Here is a find (read).
1Grade grade = grades.find(eq("student_id", 10003d)).first();
2System.out.println("Grade found:\t" + grade);
  • Here is an update with a findOneAndReplace returning the newest version of the document.
1List<Score> newScores = new ArrayList<>(grade.getScores());
2newScores.add(new Score().setType("exam").setScore(42d));
3grade.setScores(newScores);
4Document filterByGradeId = new Document("_id", grade.getId());
5FindOneAndReplaceOptions returnDocAfterReplace = new FindOneAndReplaceOptions()
6 .returnDocument(ReturnDocument.AFTER);
7Grade updatedGrade = grades.findOneAndReplace(filterByGradeId, grade, returnDocAfterReplace);
8System.out.println("Grade replaced:\t" + updatedGrade);
  • And finally here is a deleteOne.
1System.out.println(grades.deleteOne(filterByGradeId));

Final Code

MappingPojo.java (code):
1package com.mongodb.quickstart;
2
3import com.mongodb.ConnectionString;
4import com.mongodb.MongoClientSettings;
5import com.mongodb.client.MongoClient;
6import com.mongodb.client.MongoClients;
7import com.mongodb.client.MongoCollection;
8import com.mongodb.client.MongoDatabase;
9import com.mongodb.client.model.FindOneAndReplaceOptions;
10import com.mongodb.client.model.ReturnDocument;
11import com.mongodb.quickstart.models.Grade;
12import com.mongodb.quickstart.models.Score;
13import org.bson.codecs.configuration.CodecRegistry;
14import org.bson.codecs.pojo.PojoCodecProvider;
15import org.bson.conversions.Bson;
16
17import java.util.ArrayList;
18import java.util.List;
19
20import static com.mongodb.client.model.Filters.eq;
21import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
22import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
23
24public class MappingPOJO {
25
26 public static void main(String[] args) {
27 ConnectionString connectionString = new ConnectionString(System.getProperty("mongodb.uri"));
28 CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
29 CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
30 MongoClientSettings clientSettings = MongoClientSettings.builder()
31 .applyConnectionString(connectionString)
32 .codecRegistry(codecRegistry)
33 .build();
34 try (MongoClient mongoClient = MongoClients.create(clientSettings)) {
35 MongoDatabase db = mongoClient.getDatabase("sample_training");
36 MongoCollection<Grade> grades = db.getCollection("grades", Grade.class);
37
38 // create a new grade.
39 Grade newGrade = new Grade().setStudentId(10003d)
40 .setClassId(10d)
41 .setScores(List.of(new Score().setType("homework").setScore(50d)));
42 grades.insertOne(newGrade);
43 System.out.println("Grade inserted.");
44
45 // find this grade.
46 Grade grade = grades.find(eq("student_id", 10003d)).first();
47 System.out.println("Grade found:\t" + grade);
48
49 // update this grade: adding an exam grade
50 List<Score> newScores = new ArrayList<>(grade.getScores());
51 newScores.add(new Score().setType("exam").setScore(42d));
52 grade.setScores(newScores);
53 Bson filterByGradeId = eq("_id", grade.getId());
54 FindOneAndReplaceOptions returnDocAfterReplace = new FindOneAndReplaceOptions().returnDocument(ReturnDocument.AFTER);
55 Grade updatedGrade = grades.findOneAndReplace(filterByGradeId, grade, returnDocAfterReplace);
56 System.out.println("Grade replaced:\t" + updatedGrade);
57
58 // delete this grade
59 System.out.println("Grade deleted:\t" + grades.deleteOne(filterByGradeId));
60 }
61 }
62}
To start this program, you can use this maven command line in your root project (where the src folder is) or your favorite IDE.
1mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.MappingPOJO" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority"

Wrapping Up

Mapping POJOs and your MongoDB documents simplifies your life a lot when you are solving real-world problems with Java, but you can certainly be successful without using POJOs.
MongoDB is a dynamic schema database which means your documents can have different schemas within a single collection. Mapping all the documents from such a collection can be a challenge. So, sometimes, using the "old school" method and the Document class will be easier.
If you want to learn more and deepen your knowledge faster, I recommend you check out the MongoDB Java Developer Path training available for free on MongoDB University.
In the next blog post, I will show you the aggregation framework in Java.

Facebook Icontwitter iconlinkedin icon
Rate this quickstart
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Article

Java 21: Unlocking the Power of the MongoDB Java Driver With Virtual Threads


Jan 31, 2024 | 2 min read
Podcast

Scaling the Gaming Industry with Gaspard Petit of Square Enix


Mar 22, 2023 | 29 min
Article

How to Optimize Java Performance With Virtual Threads, Reactive Programming, and MongoDB


Aug 29, 2024 | 5 min read
Tutorial

Microservices Architecture: Deploy Locally With Java, Spring, and MongoDB


Aug 29, 2024 | 4 min read
Table of Contents