Overview
In this guide, you can learn how to use the MongoDB Extension for Hibernate ORM to run native queries on your MongoDB database. Instead of Hibernate Query Language (HQL) or Jakarta Persistence Query Language (JPQL), native queries allow you to use MongoDB Query Language (MQL) to specify your query. MQL is a query syntax designed for interacting with the MongoDB document-based model.
Tip
MongoDB Query Language
To learn more about MQL syntax and functionality, see MongoDB Query Language Reference in the MongoDB Server manual.
Hibernate ORM's createQuery() method does not support some MongoDB query features. The createNativeQuery() method allows you to specify database queries in MQL and bypass some operational limitations of the Hibernate ORM extension.
You can also run queries directly on your MongoClient object for expanded query functionality.
Sample Data
The examples in this guide use the Movie entity, which represents the sample_mflix.movies collection from the Atlas sample datasets. The Movie entity has the following definition:
import com.mongodb.hibernate.annotations.ObjectIdGenerator; import org.bson.types.ObjectId; import java.util.List; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; public class Movie { private ObjectId id; private String title; private String plot; private int year; private int runtime; private List<String> cast; private List<String> directors; public Movie(String title, String plot, int year, int runtime, List<String> cast, List<String> directors) { this.title = title; this.plot = plot; this.year = year; this.runtime = runtime; this.cast = cast; this.directors = directors; } public Movie() { } public ObjectId getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getPlot() { return plot; } public void setPlot(String plot) { this.plot = plot; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getRuntime() { return runtime; } public void setRuntime(int runtime) { this.runtime = runtime; } public List<String> getCast() { return cast; } public void setCast(List<String> cast) { this.cast = cast; } public List<String> getDirectors() { return directors; } public void setDirectors(List<String> directors) { this.directors = directors; } }
To learn how to create a Java application that uses the MongoDB Extension for Hibernate ORM to interact with this MongoDB sample collection, see the Get Started tutorial.
Note
Persistence Contexts
To enable Hibernate ORM to interact with the database, you must run operations inside a persistence context by using a Hibernate Session or a Jakarta Persistence EntityManager. The examples in this guide use a Session. To learn more about persistence contexts, see the Transactions and Sessions guide.
Run Native Queries
To run a native MongoDB query, specify a MongoDB Query Language (MQL) statement that includes the collection to query and your query criteria in an aggregation pipeline.
Tip
Aggregation Pipeline
To learn more about constructing aggregation pipelines and running aggregation operations, see the Aggregation Pipeline reference in the MongoDB Server manual.
MQL statements have the following format:
String mqlSyntax = """ { aggregate: "<collection to query>", pipeline: [ <aggregation pipeline stages> ] } """;
Important
$project Stage Requirements
The aggregation pipeline in your MQL statement must include a $project stage. To return the query documents as entity instances, you must specify each entity field in the $project stage, including the _id field. The Hibernate ORM extension returns the fields you project and suppresses _id when you omit it. An entity-bound query that omits _id can fail with Unknown column label [_id] because the entity identifier maps to _id. To keep the identifier available, project _id: 1.
Then, pass the MQL statement to the createNativeQuery() method.
You can use native queries to perform the following operations:
Important
Extended JSON Syntax Required
You must write native queries in Extended JSON v2 format. The Hibernate ORM extension does not support single quotes or the MongoDB Server shell regular expression syntax (/pattern/) in native queries. For example, to query with a regular expression, use the $regularExpression Extended JSON type instead of /pattern/.
Filter and Sort Document Fields
This example runs a native query on the sample_mflix.movies collection by passing an MQL statement to the createNativeQuery() method. The code specifies the following aggregation pipeline stages:
$match: Filters for documents that have a title field value of"The Parent Trap"$sort: Sorts the matching documents by theiryearfields in descending order$project: Returns each document field defined in theMovieentity
String nativeQuery = """ { aggregate: "movies", pipeline: [ { $match: { title: { $eq: "The Parent Trap" } } }, { $sort: { year: -1 } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ] } """; var results = session.createNativeQuery(nativeQuery, Movie.class) .getResultList(); for (Movie movie : results) { System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear()); }
Use Arithmetic Operators
Note
Native queries are best for arithmetic operations that are unsupported by the Hibernate ORM extension. To learn more about which arithmetic operators the Hibernate ORM extension supports, see the Query Support section of the Feature Compatibility page.
The following example runs a native query on the sample_mflix.movies collection that performs the following actions:
Specifies a
$matchstage to match documents that have ayearvalue greater than2000and aruntimefield that existsSpecifies an
$addFieldsstage to add a new field calledruntimeHoursUses the
$dividearithmetic operator to convert theruntimevalue from minutes to hours for the newruntimeHoursfieldSpecifies a
$projectstage to return each document field defined in theMovieentity, including the_idfieldPrints the
titlevalue of each updated document
String nativeQuery = """ { aggregate: "movies", pipeline: [ { $match: { year: { $gt: 2000 }, runtime: { $exists: true } } }, { $addFields: { runtimeHours: { $divide: [ "$runtime", 60 ] } }}, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1, runtimeHours: 1 }} ] } """; var results = session.createNativeQuery(nativeQuery, Movie.class) .getResultList(); for (Movie result : results) { System.out.println("Added field to movie: " + result.getTitle()); }
Tip
Arithmetic Operators
To learn more about Hibernate and MongoDB arithmetic operators, see the following resources:
Numeric arithmetic in the Hibernate ORM query guide
Arithmetic Operators in the MongoDB Server manual
Run a MongoDB Search Query
You can run native queries to perform MongoDB Search queries on your database, which are fine-grained text searches on your data. These queries provide advanced search functionality, such as matching text phrases, scoring results for relevance, and highlighting matches.
Important
You cannot run a MongoDB Search query inside a transaction.
To specify a Search query, create a Search index that covers the fields you want to query. Then, pass an aggregation pipeline to your createNativeQuery() method that includes a $search or $searchMeta stage.
Tip
MongoDB Search
To learn more about MongoDB Search queries and indexes, see MongoDB Search Overview in the MongoDB Server manual.
This example runs a Search query by passing the $search pipeline stage to the createNativeQuery() method. The code performs the following actions:
Specifies the Search index that covers the
plotfield. Ensure that you replace the<indexName>placeholder with your Search index name.Queries for documents whose
plotvalues contain the string"whirlwind romance"with no more than3words between themSpecifies a
$projectstage to return each document field defined in theMovieentity, including the_idfieldPrints the
titleandplotvalues of the matching documents
String nativeQuery = """ { aggregate: "movies", pipeline: [ { $search: { index: "<indexName>", phrase: { path: "plot", query: "whirlwind romance", slop: 3 } } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ] } """; var results = session.createNativeQuery(nativeQuery, Movie.class) .getResultList(); for (Movie result : results) { System.out.println("Title: " + result.getTitle() + ", Plot: " + result.getPlot()); }
Use Parameters in Native Queries
You can use named (:name) or ordinal (?1) parameters to specify values in your MQL statement. The following example demonstrates how to provide the title parameter value as either a named or ordinal parameter and then supply the parameter value with setParameter():
String nativeQuery = """ { aggregate: "movies", pipeline: [ { $match: { title: { $eq: :movieTitle } } }, { $sort: { year: -1 } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ] } """; var results = session.createNativeQuery(nativeQuery, Movie.class) .setParameter("movieTitle", "The Parent Trap") .getResultList(); for (Movie movie : results) { System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear()); }
String nativeQuery = """ { aggregate: "movies", pipeline: [ { $match: { title: { $eq: ?1 } } }, { $sort: { year: -1 } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ] } """; var results = session.createNativeQuery(nativeQuery, Movie.class) .setParameter(1, "The Parent Trap") .getResultList(); for (Movie movie : results) { System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear()); }
Run MongoClient Operations
If you want to run database operations that neither the createQuery() method nor the createNativeQuery() method supports, you can operate on a MongoClient object directly in your Java application. When working with the MongoClient, you can access the MongoDB Java Sync Driver's functionality.
Tip
Feature Support
To learn more about unsupported MongoDB features that you must use a MongoClient object to access, see the Feature Compatibility page.
To learn how to use the Java driver to interact with MongoDB, see the MongoDB Java Driver documentation.
Create Indexes with the MongoClient
You cannot use the Hibernate ORM extension to create indexes on a collection, but you can instantiate a MongoClient and use the Java driver's createIndex() method. The following code creates a title field index on the sample_mflix.movies collection:
// Replace the <connection URI> placeholder with your MongoDB connection URI String uri = "<connection URI>"; MongoClient mongoClient = MongoClients.create(uri); MongoDatabase db = mongoClient.getDatabase("sample_mflix"); MongoCollection<Document> collection = db.getCollection("movies"); String indexResult = collection.createIndex(Indexes.ascending("title")); System.out.println(String.format("Index created: %s", indexResult));
To learn more about how to use the Java driver to create indexes, see the Indexes guide in the Java driver documentation.
Additional Information
To learn more about the query languages discussed in this guide, see the following resources:
A Guide to Hibernate Query Language in the Hibernate ORM documentation
MongoDB Query Language Reference in the MongoDB Server manual