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
MongoDB
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Productschevron-right
MongoDBchevron-right

Building Quarkus Application with MongoDB and Panache

Aasawari Sahasrabuddhe5 min read • Published Dec 03, 2024 • Updated Dec 03, 2024
QuarkusMongoDBJava
SNIPPET
Facebook Icontwitter iconlinkedin icon
java logo
Rate this quickstart
star-empty
star-empty
star-empty
star-empty
star-empty
Building applications with frameworks and libraries always makes the job simpler. And who doesn't like a simple life when it comes to building complicated applications? When it comes to Java applications, choosing Spring Data as the framework helps you reduce boilerplate code for setting up the configurations. Similar to Spring, to build Quarkus applications, you can make use of Panache. Panache is a Quarkus-specific library that simplifies the development of your Hibernate-based persistence layer.
Panache in Quarkus simplifies data access by minimizing boilerplate with built-in CRUD operations and type-safe queries. It supports both the Active Record and Repository patterns, allowing flexibility in architecture. Panache is tightly integrated with Quarkus, leveraging fast startup times and a low memory footprint, making it ideal for cloud-native and serverless environments. It also provides easy pagination, supports dynamic and named queries, and works seamlessly with Hibernate ORM and JPA, enhancing productivity while keeping code clean and efficient.
In this tutorial, we will be making a Quarkus application with Panache to perform some basic CRUD with aggregations to show the efficiency of working with Panache. The API allows you to perform basic CRUD operations like adding, updating, finding, and deleting books. It also supports aggregation to the group and counts books by genre.

Prerequisites

  1. A free Atlas cluster. You can create your first Atlas cluster for absolutely free!
  2. Java version 21 and above. Click on Downloads for the latest version.
  3. An IDE of your choice.
  4. Maven or Gradle as per choice.

Setting up the project

Before we get into the actual implementation part of the APIs, let's consider two of the most important things.
  1. You can create your free cluster by following the steps mentioned in the documentation or using an existing cluster.
  2. Create a Quarkus project with Maven using the below command.
1mvn io. quarkus:quarkus-maven-plugin:create \
2 -DprojectGroupId=io.quarkus.platform \
3 -DprojectArtifactId=quarkus-bom \
4 -DclassName="com.example.BookResource" \
5 -Dpath="/books"
3. Now, add the below dependencies to the pom.xml.
1 <dependencies>
2 <dependency>
3 <groupId>io.quarkus</groupId>
4 <artifactId>quarkus-arc</artifactId>
5 </dependency>
6 <dependency>
7 <groupId>io.quarkus</groupId>
8 <artifactId>quarkus-rest</artifactId>
9 </dependency>
10 <dependency>
11 <groupId>io.quarkus</groupId>
12 <artifactId>quarkus-rest-client-jackson</artifactId>
13 <version>3.16.2</version>
14 </dependency>
15 <dependency>
16 <groupId>io.quarkus</groupId>
17 <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
18 <version>3.15.1</version>
19 </dependency>
20 <dependency>
21 <groupId>io.rest-assured</groupId>
22 <artifactId>rest-assured</artifactId>
23 <scope>test</scope>
24 </dependency>
25
26 <dependency>
27 <groupId>io.quarkus</groupId>
28 <artifactId>quarkus-mongodb-panache</artifactId>
29 </dependency>
30
31 </dependencies>
4. Build the complete application and download the dependencies:
1mvn clean install

Creating REST API endpoints

Once the project is set up, the next step is to add the API endpoints. In this tutorial, we will use the Book collection from the Atlas cluster. The model class in the Quarkus project will add the fields inside the collection, and the next step will be to perform operations on the collection.
The Book collection in the Atlas collection will look like the following:
1{
2_id: ..
3title: ..
4author: ..
5genre: ..
6year: ..
7}
API endpoints
  • Insert one book: The first step will be to insert the documents inside the collection. To do so, we need to add the function in the resource class in the project. A resource class is a class that implements the PanacheRepository and provides methods to manipulate entities.
Add the below code to the resource class, which injects the repository class to implement the methods, and then create the POST call.
1 @Inject
2 BookRepository bookRepository;
3 @POST
4 public Response addBook(Book book) {
5 bookRepository.persist(book);
6 return Response.status(Response.Status.CREATED).entity(book).build();
7 }
This would insert a simple document at a time inside the collection.
The BookRepository class with the below code:
1import com.quarkusWithPanache.model.Book;
2import io.quarkus.mongodb.panache.PanacheMongoRepository;
3import jakarta.enterprise.context.ApplicationScoped;
4
5@ApplicationScoped
6public class BookRepository implements PanacheMongoRepository<Book> {
7}
  • Bulk write: The insert method will insert the documents one by one inside the collection. If there are hundreds or thousands of documents, it will take a long time to insert the documents. To save time and resources with every call, the bulk write will insert all the documents in one go. To do so, add the below code, which will perform the bulk insert.
1 @POST
2 @Path("/bulk")
3 public Response bulkAddBooks(List<Book> books) {
4 // Prepare documents for bulk write
5 List<Document> documents = new ArrayList<>();
6 for (Book book : books) {
7 documents.add(new Document("title", book.title)
8 .append("author", book.author)
9 .append("genre", book.genre)
10 .append("year", book.year));
11 }
12 getCollection().insertMany(documents);
13
14 return Response.status(Response.Status.CREATED).entity(books).build();
15 }
The getCollection method returns the database and collection name from import com.mongodb.client.MongoCollection package.
  • Find all books: Once all the books are inserted inside the collection, the next step is to retrieve the documents from the collection. To get all the books, create the below API call as:
1@GET
2 public List<Book> getAllBooks() {
3 return bookRepository.listAll();
4 }
  • Find one book by ID: To retrieve a specific book from the collection based on the _id, the below API call would fetch a single document that matches the condition.
1@GET
2 @Path("/{id}")
3 public Book getBookById(@PathParam("id") String id) {
4 return bookRepository.findById(new ObjectId(id));
5 }
  • Delete book by ID: Similar to retrieving a single document from the collection, the delete one will delete the single document based on the matching _id. To do so, use the below-created API.
1 @DELETE
2 @Path("/{id}")
3 public Response deleteBook(@PathParam("id") String id) {
4 boolean deleted = bookRepository.deleteById(new ObjectId(id));
5 return deleted ? Response.noContent().build() : Response.status(Response.Status.NOT_FOUND).build();
6 }
  • Update a book: Finally, to update the document based on the _id value, use the below code with the updated field values.
1@PUT
2 @Path("/{id}")
3 public Response updateBook(@PathParam("id") String id, Book book) {
4 Book entity = bookRepository.findById(new ObjectId(id));
5 if (entity == null) {
6 return Response.status(Response.Status.NOT_FOUND).build();
7 }
8 entity.title = book.title;
9 entity.author = book.author;
10 entity.genre = book.genre;
11 entity.year = book.year;
12 bookRepository.update(entity);
13 return Response.ok(entity).build();
14 }
  • Aggregation (genre count): Apart from performing basic CRUD operations, if you wish to perform an aggregation operation, you can use the code as below. As an example, this aggregation will perform a genre field and count the genres.
1@GET
2 @Path("/aggregate/genre-count")
3 public Response countBooksByGenre() {
4
5 List<Document> pipeline = new ArrayList<>();
6 pipeline.add(new Document("$group", new Document("_id", "$genre")
7 .append("count", new Document("$sum", 1))));
8
9 List<Document> result = getCollection()
10 .aggregate(pipeline)
11 .into(new ArrayList<>());
12
13 return Response.ok(result).build();
14 }

Testing the API

To test the API, we can use the following cURL commands to interact with the server. Make sure the application is running on http://localhost:8080 before sending the requests.
Insert one book:
1curl -X POST "http://localhost:8080/books" -H "Content-Type: application/json" -d '{
2 "title": "Quarkus in Action",
3 "author": "John Doe",
4 "genre": "Programming",
5 "year": 2023
6}'
Bulk insert
1curl -X POST http://localhost:8080/books/bulk \
2 -H "Content-Type: application/json" \
3 -d '[
4 {
5 "title": "The Midnight Library",
6 "author": "Matt Haig",
7 "genre": "Fiction",
8 "year": 2020
9 },
10 {
11 "title": "Sapiens: A Brief History of Humankind",
12 "author": "Yuval Noah Harari",
13 "genre": "Non-Fiction",
14 "year": 2011
15 },
16 .......
17 ]'
Find all books

:

1curl -X GET "http://localhost:8080/books" | jq
Find one book:
1curl -X GET "http://localhost:8080/books/672f873b421eaa0c3e4da49f" | jq
Delete one book:
1curl -X DELETE "http://localhost:8080/books/673f81b65750de0757a4bbfb" | jq
Update one book:
1curl -X PUT "http://localhost:8080/books/672f856f421eaa0c3e4da49e" \
2 -H "Content-Type: application/json" \
3 -d '{
4 "title": "Quarkus in Action",
5 "author": "John Doe",
6 "genre": "Programming",
7 "year": 2021
8 }'
Aggregation: Genre count
1curl -X GET "http://localhost:8080/books/aggregate/genre-count" | jq
This would give the output for the count of all the genres.
The complete code for the application is available on the GitHub repository.

Conclusion

In this tutorial, we explored how to harness the power of Panache in a Quarkus application to simplify CRUD operations and implement aggregation queries. By leveraging Panache's built-in functionalities, we reduced boilerplate code, making development faster and more efficient. From inserting single and multiple documents to retrieving, updating, and deleting them, we demonstrated how Panache integrates seamlessly with MongoDB to handle data operations. Additionally, we showcased how to perform aggregations, such as counting books by genre, to extract meaningful insights from data.
Panache's ability to work with Hibernate ORM and JPA, combined with Quarkus's low memory footprint and fast startup times, makes it an ideal choice for building cloud-native, serverless, and highly performant applications. With Panache, developers can focus on business logic while maintaining clean and readable code.
If you wish to learn more about MongoDB and its concepts, like vector search, read our tutorial on MongoDB Vector Search with Quarkus on the MongoDB Developer Center, and find more interesting topics. For any questions related to the above or MongoDB, don’t forget to pay a visit to the MongoDB community forum and be a part of an interesting discussion.
Top Comments in Forums
There are no comments on this article yet.
Start the Conversation

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

Spring Data Unlocked: Getting Started With Java and MongoDB


Nov 11, 2024 | 5 min read
Article

Using MongoDB Change Streams in Java


Aug 28, 2024 | 6 min read
Tutorial

Real Time Data in a React JavaScript Front-End with Change Streams


Sep 09, 2024 | 6 min read
Tutorial

How to Import Data Into MongoDB With mongoimport


Jun 12, 2024 | 15 min read
Table of Contents