Mongo DB Crud Operation using Java

MongoDB CRUD Operations with Java: Complete Guide (2026)

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)

  1. Connect to MongoDB: The constructor uses a MongoDB URI with authentication (authSource=admin) to connect to the springdb database and the products collection.
  2. Insert a document: Gson converts the ProductDTO into JSON, then Document.parse() creates a MongoDB document, and insertOne() saves it.
  3. Fetch one document: A filter Document with the productId is passed to find(). The cursor returns the matching document.
  4. Fetch all documents: coll.find() with no filter returns every document; a while loop converts each into a ProductDTO.
  5. Aggregation (group by): A pipeline with $group groups documents by userId, counts products, and sums total price.
  6. Date-range filter: A filter uses $gte and $lte to match documents created between two dates.
  7. Delete: deleteOne() with a filter removes the matching document and returns the count of deleted records.
  8. Update: updateOne() with $set updates specific fields without replacing the whole document.
  9. 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: