Tutorial: Build a Quarkus Application with Panache and MongoDB

For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt

Tutorial: Build a Quarkus Application with Panache and MongoDB

Overview

Panache is a Quarkus framework-specific library that simplifies the development of Hibernate-based persistence layers. It reduces boilerplate code by providing built-in CRUD operations and type-safe queries.

Panache supports both the Active Record pattern, which embeds database operations directly in entity classes, and the Repository pattern, which separates data access logic into dedicated repository classes. It integrates with Quarkus to provide fast startup times and a low memory footprint. Panache works with Hibernate Object-Relational Mapping (ORM) and Java Persistence API (JPA) to simplify data access while keeping code clean.

In this tutorial, you build a Quarkus application with Panache to perform CRUD operations and aggregations on a MongoDB database. The application allows you to add, update, find, and delete books, as well as count books by genre.

Tutorial

In this tutorial, you perform the following actions:

  • Verify the prerequisites

  • Set up the project

  • Create the data model

  • Create REST API endpoints

  • Test the API

  • Verify the prerequisites

Before you begin, ensure you have the following:

  • A MongoDB Atlas account with a configured cluster. To learn how to set up an Atlas cluster, see the MongoDB [Get Started](https://www.mongodb.com/docs/get-started.md#std-label-unified-get-started guide.

  • Java version 21 or later. To learn more about installing Java, see the Oracle website.

  • Your preferred IDE.

  • Maven to manage project dependencies.

  • Set up the project

Create a folder to hold your Quarkus project. Navigate into this directory and create a Quarkus project with Maven by running the following command:

bash mvn io.quarkus:quarkus-maven-plugin:create \ -DprojectGroupId=io.quarkus.platform \ -DprojectArtifactId=quarkus-bom \ -DclassName="com.example.BookResource" \ -Dpath="/books"

Add the following dependencies to your pom.xml file:

xml <dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-arc</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-rest</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-rest-client-jackson</artifactId> <version>3.16.2</version> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-reactive-jackson</artifactId> <version>3.15.1</version> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-mongodb-panache</artifactId> </dependency> </dependencies>

Build the application and download the dependencies by running the following command in your project directory:

bash mvn clean install

  1. Create the data model

First, from the root directory of your project, navigate to src/main/java/com/<package>. Create a Book.java file in this directory . Inside this file, define the Book class as shown in the following code:

```java import io.quarkus.mongodb.panache.PanacheMongoEntity; import io.quarkus.mongodb.panache.common.MongoEntity;

@MongoEntity(collection = "books") public class Book extends PanacheMongoEntity { public String title; public String author; public String genre; public int year;

   public Book() {
   }

} ```

This class represents a book document in the MongoDB collection with fields for the title, author, genre, and year.

  1. Create REST API endpoints

Create a BookRepository.java file in your package directory. Inside this file, define the BookRepository class as shown in the following code:

```java import com.quarkusWithPanache.model.Book; import io.quarkus.mongodb.panache.PanacheMongoRepository; import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped public class BookRepository implements PanacheMongoRepository { } ```

Next, create a BookResource.java file in your package directory. Inside this file, define a resource class that uses the BookRepository interface you created in the preceding example, as shown in the following code:

```java import com.mongodb.client.MongoClient; import com.mongodb.client.MongoCollection; import com.quarkusWithPanache.model.Book; import com.quarkusWithPanache.repository.BookRepository;

import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; import org.bson.Document; import org.bson.types.ObjectId;

import java.util.ArrayList; import java.util.List;

@Path("/books") public class BookResource {

   @Inject
   BookRepository bookRepository;

   @Inject
   MongoClient mongoClient;

   private MongoCollection<Document> getCollection() {
       return mongoClient.getDatabase("test").getCollection("books");
   }

   @Inject
   public BookResource(BookRepository bookRepository) {
       this.bookRepository = bookRepository;
   }

   // Define API endpoints here

} ```

The following sections show how to implement various API endpoints for CRUD operations and aggregations. You can add the code for each endpoint below the highlighted line in the preceding example.

##### Insert one book

You can insert a single book by adding the following code to your resource class:

```java @Inject BookRepository bookRepository;

@POST public Response addBook(Book book) { bookRepository.persist(book); return Response.status(Response.Status.CREATED).entity(book).build(); } ```

##### Bulk insert

You can insert multiple books at once by adding the following code to your resource class:

```java @POST @Path("/bulk") public Response bulkAddBooks(List books) { // Prepare documents for bulk write List documents = new ArrayList<>(); for (Book book : books) { documents.add(new Document("title", book.title) .append("author", book.author) .append("genre", book.genre) .append("year", book.year)); } getCollection().insertMany(documents);

   return Response.status(Response.Status.CREATED).entity(books).build();

} ```

The getCollection method returns the database and collection name from the com.mongodb.client.MongoCollection package.

##### Find all books

You can retrieve all books by adding the following code to your resource class:

java @GET public List<Book> getAllBooks() { return bookRepository.listAll(); }

##### Find one book by ID

You can retrieve a specific book by its _id value by adding the following code to your resource class:

java @GET @Path("/{id}") public Book getBookById(@PathParam("id") String id) { return bookRepository.findById(new ObjectId(id)); }

##### Delete a book by ID

You can delete a book by its _id value by adding the following code to your resource class:

java @DELETE @Path("/{id}") public Response deleteBook(@PathParam("id") String id) { boolean deleted = bookRepository.deleteById(new ObjectId(id)); return deleted ? Response.noContent().build() : Response.status(Response.Status.NOT_FOUND).build(); }

##### Update a book

You can update a book by its _id value by adding the following code to your resource class:

java @PUT @Path("/{id}") public Response updateBook(@PathParam("id") String id, Book book) { Book entity = bookRepository.findById(new ObjectId(id)); if (entity == null) { return Response.status(Response.Status.NOT_FOUND).build(); } entity.title = book.title; entity.author = book.author; entity.genre = book.genre; entity.year = book.year; bookRepository.update(entity); return Response.ok(entity).build(); }

##### Aggregate by genre

You can count books by genre by adding the following aggregation code to your resource class:

```java @GET @Path("/aggregate/genre-count") public Response countBooksByGenre() { List pipeline = new ArrayList<>(); pipeline.add(new Document("$group", new Document("_id", "$genre") .append("count", new Document("$sum", 1))));

   List<Document> result = getCollection()
           .aggregate(pipeline)
           .into(new ArrayList<>());

   return Response.ok(result).build();

} ```

  1. Test the API

Start your application on http://localhost:8080 by running the following command from the root directory of your project:

bash mvn spring-boot:run

You can test the API endpoints by running the following curl commands:

##### Insert one book

The following curl command shows how to insert a single book:

bash curl -X POST "http://localhost:8080/books" -H "Content-Type: application/json" -d '{ "title": "Quarkus in Action", "author": "John Doe", "genre": "Programming", "year": 2023 }'

##### Bulk insert

The following curl command shows how to insert multiple books:

bash curl -X POST http://localhost:8080/books/bulk \ -H "Content-Type: application/json" \ -d '[ { "title": "The Midnight Library", "author": "Matt Haig", "genre": "Fiction", "year": 2020 }, { "title": "Sapiens: A Brief History of Humankind", "author": "Yuval Noah Harari", "genre": "Non-Fiction", "year": 2011 } ]'

##### Find all books

The following curl command shows how to retrieve all books:

bash curl -X GET "http://localhost:8080/books" | jq

##### Find one book

The following curl command shows how to retrieve a specific book:

bash curl -X GET "http://localhost:8080/books/672f873b421eaa0c3e4da49f" | jq

##### Delete a book

The following curl command shows how to delete a book:

bash curl -X DELETE "http://localhost:8080/books/673f81b65750de0757a4bbfb" | jq

##### Update a book

The following curl command shows how to update a book:

bash curl -X PUT "http://localhost:8080/books/672f856f421eaa0c3e4da49e" \ -H "Content-Type: application/json" \ -d '{ "title": "Quarkus in Action", "author": "John Doe", "genre": "Programming", "year": 2021 }'

##### Aggregate by genre

The following curl command shows how to count books by genre:

bash curl -X GET "http://localhost:8080/books/aggregate/genre-count" | jq

Tip: Using jq to format JSON output

Use the jq tool, as shown in the preceding examples, to format the JSON output from the API for better readability. You can install jq by following the instructions on the jq website.

Additional Resources

To view the complete version of the example in this tutorial, see the quarkus-panache-with-mongodb Github repository.

To learn more about Panache, see the MongoDB with Panache documentation on the Quarkus website.