MongoDB CRUD Operations with Java: Complete Guide
In this tutorial, you will learn how to perform CRUD operations in MongoDB using Java — insert, fetch, update, delete, and run aggregation pipelines. The example uses the MongoDB Java driver, Google Gson for JSON conversion, and Lombok to reduce boilerplate code.
By the end, you will have a working MongoQueryDao class that connects to
MongoDB, manages product data, and performs advanced queries such as group-by-userId
aggregation and date-range filtering.
Overview
The MongoQueryDao class is designed to interact with a MongoDB database. It
connects to a MongoDB instance, performs CRUD operations (Create, Read, Update, Delete),
and processes product data.
The core functionality of this class includes inserting, fetching, updating, and deleting product records, as well as performing aggregation operations such as calculating totals and fetching records within a date range.
Key Features
- Establishes a connection to MongoDB with user authentication.
- Supports various operations such as inserting, updating, deleting, and fetching data from MongoDB.
- Uses the MongoDB Java driver and integrates with Spring's HTTP response framework for API responses.
- Handles different types of queries, including aggregation and date-range filters.
- Converts POJOs to MongoDB documents seamlessly using Gson.
Project Structure
The project follows a flat package structure under com.example for simplicity.
Below is the project layout:
The project contains four Java classes:
MainApplication, MongoQueryDao,
ProductDTO, and APIResponseDTO.
pom.xml — Maven Dependencies
Add these dependencies to your pom.xml. They provide the MongoDB Java driver,
Lombok for boilerplate reduction, Spring Web for HttpStatus, and Gson for JSON
conversion.
<dependencies>
<!-- MongoDB Java Driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.14</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<!-- Spring Boot Starter Web (for HttpStatus) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.4.1</version>
</dependency>
<!-- Gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.8</version>
</dependency>
</dependencies>
ProductDTO.java
The ProductDTO class is a Plain Old Java Object (POJO) that represents a
product document stored in MongoDB. Thanks to Lombok's @Data annotation, all
getters, setters, toString(), equals(), and hashCode()
methods are generated automatically.
package com.example;
import lombok.Data;
@Data
public class ProductDTO {
private String productId;
private String name;
private int quantity;
private double basePrice;
private double totalPrice;
private String createDate;
private String userId;
}
Each field maps directly to a MongoDB document field. Gson handles the conversion between the Java object and the JSON stored in MongoDB.
APIResponseDTO.java
APIResponseDTO is a generic response wrapper used by every method in
MongoQueryDao. It carries the HTTP status, the payload, and a human-readable
message. Lombok's @Value makes it immutable, and @Builder
provides a fluent builder API.
package com.example;
import org.springframework.http.HttpStatus;
import lombok.Builder;
import lombok.Value;
@Value
@Builder
public class APIResponseDTO<T> {
private HttpStatus status;
private T payLoad;
private String message;
}
The <T> generic type allows the same wrapper to carry any payload —
a single ProductDTO, a List of products, a
Document from aggregation, or null.
MongoQueryDao.java
This is the main data access class. It connects to MongoDB in the constructor, then exposes eight methods for CRUD and aggregation operations.
package com.example;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bson.Document;
import org.springframework.http.HttpStatus;
import com.google.gson.Gson;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
public class MongoQueryDao {
private MongoDatabase mongoDB;
private MongoCollection<Document> coll;
private Gson gson = new Gson();
public MongoQueryDao() {
String username = "adminUser";
String password = "securePassword123";
String database = "springdb";
String uri = "mongodb://" + username + ":" + password
+ "@localhost:27017/?authSource=admin";
@SuppressWarnings("resource")
MongoClient mongoClient = new MongoClient(new MongoClientURI(uri));
mongoDB = mongoClient.getDatabase(database);
coll = mongoDB.getCollection("products");
}
public APIResponseDTO<?> addProduct(ProductDTO productDTO) {
coll.insertOne(Document.parse(gson.toJson(productDTO)));
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Successfully Inserted")
.payLoad(null)
.build();
}
public APIResponseDTO<?> fetchProduct(String productId) {
Document filter = new Document();
filter.append("productId", productId);
FindIterable<Document> findIterable = coll.find(filter);
MongoCursor<Document> cursor = findIterable.iterator();
if (cursor.hasNext()) {
Document document = cursor.next();
ProductDTO product = gson.fromJson(document.toJson(), ProductDTO.class);
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Fetch Successfully")
.payLoad(product)
.build();
} else {
return APIResponseDTO.builder()
.status(HttpStatus.NO_CONTENT)
.message("No Product Found")
.payLoad(null)
.build();
}
}
public APIResponseDTO<?> fetchProducts() {
List<ProductDTO> products = new ArrayList<ProductDTO>();
FindIterable<Document> findIterable = coll.find();
MongoCursor<Document> cursor = findIterable.iterator();
while (cursor.hasNext()) {
Document document = cursor.next();
ProductDTO product = gson.fromJson(document.toJson(), ProductDTO.class);
products.add(product);
}
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Fetch Successfully")
.payLoad(products)
.build();
}
public APIResponseDTO<?> fetchTotalAmountAndProductsByUserId() {
List<Document> products = new ArrayList<Document>();
List<Document> pipelines = Arrays.asList(
new Document("$group",
new Document("_id", "$userId")
.append("totalProducts", new Document("$sum", 1L))
.append("totalAmount", new Document("$sum", "$totalPrice"))
)
);
MongoCursor<Document> cursor = coll.aggregate(pipelines).iterator();
while (cursor.hasNext()) {
Document document = cursor.next();
products.add(document);
}
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Fetch Successfully")
.payLoad(products)
.build();
}
public APIResponseDTO<?> fetchProductsByDate(String fromDate, String toDate) {
List<Document> products = new ArrayList<Document>();
Document dateFilter = new Document();
dateFilter.append("createDate",
new Document("$gte", fromDate).append("$lte", toDate));
MongoCursor<Document> cursor = coll.find(dateFilter).iterator();
while (cursor.hasNext()) {
Document document = cursor.next();
products.add(document);
}
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Fetch Successfully")
.payLoad(products)
.build();
}
public APIResponseDTO<?> deleteProduct(String productId) {
Document deleteFilter = new Document("productId", productId);
DeleteResult result = coll.deleteOne(deleteFilter);
long count = result.getDeletedCount();
if (count > 0) {
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Delete Successfully")
.payLoad(null)
.build();
} else {
return APIResponseDTO.builder()
.status(HttpStatus.BAD_REQUEST)
.message("Delete Failed")
.payLoad(null)
.build();
}
}
public APIResponseDTO<?> updateProduct(ProductDTO productDTO) {
Document updateFilter = new Document("productId", productDTO.getProductId());
Document updateDocument = new Document(
new Document("$set", Document.parse(gson.toJson(productDTO)))
);
UpdateResult result = coll.updateOne(updateFilter, updateDocument);
if (result.getMatchedCount() > 0) {
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Update Successfully")
.payLoad(productDTO)
.build();
} else {
return APIResponseDTO.builder()
.status(HttpStatus.BAD_REQUEST)
.message("Updation Failed")
.payLoad(productDTO)
.build();
}
}
public APIResponseDTO<?> totalSaleProductInYearAndTopOneCustomer(String yearOnly) {
String startDate = yearOnly + "-01-01 00:00:01";
String endDate = yearOnly + "-12-31 23:59:59";
List<Document> pipeline = Arrays.asList(
new Document("$match",
new Document("createDate",
new Document("$gte", startDate)
.append("$lte", endDate))),
new Document("$group",
new Document("_id", "$userId")
.append("totalProducts", new Document("$sum", 1L))
.append("totalAmount", new Document("$sum", "$totalPrice"))),
new Document("$sort", new Document("totalAmount", -1L)),
new Document("$limit", 1L)
);
MongoCursor<Document> cursor = coll.aggregate(pipeline).iterator();
if (cursor.hasNext()) {
Document document = cursor.next();
return APIResponseDTO.builder()
.status(HttpStatus.OK)
.message("Fetch Successfully")
.payLoad(document)
.build();
} else {
return APIResponseDTO.builder()
.status(HttpStatus.BAD_REQUEST)
.message("No Records Found")
.payLoad(null)
.build();
}
}
}
MainApplication.java
The entry point that demonstrates all eight operations in sequence — inserting dummy products, then running each query.
package com.example;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class MainApplication {
public static void main(String[] args) {
MongoQueryDao mongoQueryDao = new MongoQueryDao();
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 1. Create dummy products to add in products collection
for (int i = 1; i < 100; i++) {
ProductDTO p = new ProductDTO();
p.setName("PRODUCT" + i);
p.setBasePrice(i + 5);
p.setQuantity(i);
p.setTotalPrice(p.getBasePrice() * p.getQuantity());
p.setCreateDate(now.minusHours(i).format(formatter));
int d = (int) (Math.random() * 10);
int id = d == 0 ? 11 : d;
p.setUserId("USERID" + id);
p.setProductId("" + i);
mongoQueryDao.addProduct(p);
}
// 2. Fetch data based on productId
System.out.println(mongoQueryDao.fetchProduct("11"));
// 3. Fetch all products
System.out.println(mongoQueryDao.fetchProducts());
// 4. Fetch total amount and products by userId
System.out.println(mongoQueryDao.fetchTotalAmountAndProductsByUserId());
// 5. Fetch data based on date filter
String fromDate = "2025-02-10 19:03:43";
String toDate = "2025-02-14 11:03:43";
System.out.println(mongoQueryDao.fetchProductsByDate(fromDate, toDate));
// 6. Delete a data from mongo DB
System.out.println(mongoQueryDao.deleteProduct("1"));
// 7. Update a data from mongo DB
ProductDTO update = new ProductDTO();
update.setProductId("7");
update.setName("PRODUCT56");
update.setBasePrice(62);
update.setCreateDate("2025-02-12 05:03:43");
update.setQuantity(3);
update.setTotalPrice(update.getQuantity() * update.getBasePrice());
update.setUserId("USERID7");
System.out.println(mongoQueryDao.updateProduct(update));
// 8. Total Sale in year and find the top 1 customer
System.out.println(mongoQueryDao
.totalSaleProductInYearAndTopOneCustomer("2025"));
}
}
How It Works (Step-by-Step)
-
Connect to MongoDB: The constructor uses a MongoDB URI with
authentication (
authSource=admin) to connect to thespringdbdatabase and theproductscollection. -
Insert a document: Gson converts the
ProductDTOinto JSON, thenDocument.parse()creates a MongoDB document, andinsertOne()saves it. -
Fetch one document: A filter
Documentwith theproductIdis passed tofind(). The cursor returns the matching document. -
Fetch all documents:
coll.find()with no filter returns every document; awhileloop converts each into aProductDTO. -
Aggregation (group by): A pipeline with
$groupgroups documents byuserId, counts products, and sums total price. -
Date-range filter: A filter uses
$gteand$lteto match documents created between two dates. -
Delete:
deleteOne()with a filter removes the matching document and returns the count of deleted records. -
Update:
updateOne()with$setupdates specific fields without replacing the whole document. -
Top customer: A multi-stage pipeline
(
$match → $group → $sort → $limit) finds the top customer of the year.
Frequently Asked Questions
How do I connect to MongoDB from Java?
Use MongoClient from the MongoDB Java driver with a MongoDB URI. For
authenticated connections, use
mongodb://username:password@localhost:27017/?authSource=admin, then call
mongoClient.getDatabase(dbName) and getCollection(collectionName).
How do I insert a document into MongoDB in Java?
Convert your POJO to JSON using Gson, then use Document.parse(json) and call
collection.insertOne(document). This inserts the document directly into the
MongoDB collection.
How do I perform MongoDB aggregation in Java?
Build a list of Document objects representing the pipeline stages
($match, $group, $sort, $limit), then
call collection.aggregate(pipelineList).iterator() to execute the aggregation.
What is the difference between updateOne and replaceOne in MongoDB?
updateOne uses $set or other operators to modify specific fields
while preserving others. replaceOne replaces the entire document except for
the _id. For partial updates, use updateOne with
$set.
How do I filter MongoDB documents by date range in Java?
Use a Document filter with $gte (greater than or equal) and
$lte (less than or equal) operators:
new Document("createDate", new Document("$gte", fromDate).append("$lte", toDate)).
Then call collection.find(filter).
Conclusion
In this tutorial, you learned how to perform all core MongoDB CRUD operations in
Java — insert, fetch, update, delete — plus advanced aggregation pipelines using
$match, $group, $sort, and $limit.
The MongoQueryDao class provides a clean, reusable data access layer that
uses Gson for JSON conversion and Lombok to keep the model classes concise. You can extend
this project with pagination, indexes, connection pooling, or a Spring Boot REST API to
build a full production-grade service.
Related topics: Spring Data MongoDB, MongoDB Aggregation Framework, MongoDB Indexes, MongoClientSettings, Reactive MongoDB Driver, Java REST API with MongoDB
No comments:
Post a Comment