Overview
在本指南中,您可以学习如何使用 MongoDB Extension for Hibernate ORM 来指定数据库查询。
您可以通过创建查询过滤来优化查询返回的文档设立。查询过滤是一个表达式,用于指定MongoDB在读取或写入操作中用于匹配文档的搜索条件。要创建MongoDB查询筛选器,请使用 Hibernate Query Language (HQL) 或 Jakarta Persistence Query Language (JPQL) 语句。
样本数据
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 List<String> cast; public Movie(String title, String plot, int year, List<String> cast) { this.title = title; this.plot = plot; this.year = year; this.cast = cast; } 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 List<String> getCast() { return cast; } public void setCast(List<String> cast) { this.cast = cast; } }
要学习;了解如何创建使用MongoDB Extension for Hibernate ORM 与此MongoDB示例集合交互的Java应用程序,请参阅入门教程。
重要
持久性上下文
启用Hibernate ORM 能够与数据库交互,您必须使用 Hibernate Session 或 Jakarta Persistence EntityManager 在持久性上下文中运行操作。使用 HQL 定义会话查询,使用 JPQL 定义实体经理查询。
Before running the examples in this guide, ensure that you add persistence context and transaction management code to your application that resembles the following code:
// Replace <persistence unit> with the name of your persistence unit in the persistence.xml file EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence unit>"); EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin(); // ... Perform CRUD operations here entityManager.getTransaction().commit(); entityManager.close(); emf.close;
要使用 EntityManager,您必须创建一个声明持久性单元的 persistence.xml文件。要学习;了解更多信息,请参阅 Hibernate ORM 文档中的使用 JPA 标准 API 的教程。
运行查询
要查询MongoDB数据,请在会话或实体经理上调用 createQuery() 方法。然后,在 Hibernate Query Language (HQL) 或 Jakarta Persistence Query Language (JPQL)声明中指定匹配条件。
本节介绍如何执行以下查询操作:
检索所有文档
要从集合中检索所有文档,请将基本 select声明传递给 createQuery() 方法。在此声明中,指定表示要查询的集合的实体。
The following example retrieves the title values of all documents from the sample_mflix.movies collection by querying the Movie entity:
var allDocs = session.createQuery("select title from Movie", String.class) .getResultList(); for (var t : allDocs) { System.out.println("Title: " + t); }
Title: A Corner in Wheat Title: Gertie the Dinosaur Title: The Perils of Pauline Title: Civilization Title: Where Are My Children? ...
var allDocs = entityManager.createQuery("select m.title from Movie m", String.class) .getResultList(); for (var t : allDocs) { System.out.println("Title: " + t); }
Title: A Corner in Wheat Title: Gertie the Dinosaur Title: The Perils of Pauline Title: Civilization Title: Where Are My Children? ...
检索匹配文档
要检索匹配特定条件的文档,请将带有 where 子句的 SELECT声明传递给 createQuery() 方法。在此声明中,指定表示要查询的集合的实体以及匹配条件。
The following example retrieves documents that have a title value of "Romeo and Juliet" from the sample_mflix.movies collection:
var matchingDocs = session.createQuery("from Movie where title = :t", Movie.class) .setParameter("t", "Romeo and Juliet") .getResultList(); for (var m : matchingDocs) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Romeo and Juliet, Year: 1936 Title: Romeo and Juliet, Year: 1968
var matchingDocs = entityManager.createQuery("select m from Movie m where m.title = :t", Movie.class) .setParameter("t", "Romeo and Juliet") .getResultList(); for (var m : matchingDocs) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Romeo and Juliet, Year: 1936 Title: Romeo and Juliet, Year: 1968
Retrieve One Document
要检索匹配特定条件的单个文档,请将 getSingleResult() 方法链接到 createQuery() 方法。
The following example retrieves a single document that has a title value of "Best in Show" from the sample_mflix.movies collection:
var singleResult = session.createQuery("from Movie where title = :t", Movie.class) .setParameter("t", "Best in Show") .getSingleResult(); System.out.println("Title: " + singleResult.getTitle() + ", Year: " + singleResult.getYear());
Title: Best in Show, Year: 2000
var singleResult = entityManager.createQuery("select m from Movie m where m.title = :t", Movie.class) .setParameter("t", "Best in Show") .getSingleResult(); System.out.println("Title: " + singleResult.getTitle() + ", Year: " + singleResult.getYear());
Title: Best in Show, Year: 2000
运行条件API查询
您可以使用 Jakarta Persistence Criteria API 以编程方式构建类型安全的查询,而不是使用 HQL 或 JPQL 声明创建查询筛选条件。
要使用 Criteria API 创建查询,请执行以下操作:
从会话或实体管理器创建
CriteriaBuilder对象。从构建器创建一个
CriteriaQuery对象,并指定要查询的实体。使用
CriteriaQuery类提供的查询方法来指定查询条件。
提示
要学习;了解有关 Criteria API 的更多信息,请参阅 Jakarta EE 文档中的使用 Criteria API创建查询。
The following example uses the Criteria API to retrieve all documents that have a year value of 1925 from the sample_mflix.movies collection:
CriteriaBuilder cb = session.getCriteriaBuilder(); CriteriaQuery<Movie> cq = cb.createQuery(Movie.class); Root<Movie> movieRoot = cq.from(Movie.class); cq.select(movieRoot).where(cb.equal(movieRoot.get("year"), 1925)); session.createQuery(cq).getResultList() .forEach(m -> System.out.println(m.getTitle()));
Lady Windermere's Fan Clash of the Wolves Grass: A Nation's Battle for Life
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Movie> cq = cb.createQuery(Movie.class); Root<Movie> movieRoot = cq.from(Movie.class); cq.select(movieRoot).where(cb.equal(movieRoot.get("year"), 1925)); entityManager.createQuery(cq).getResultList() .forEach(m -> System.out.println(m.getTitle()));
Lady Windermere's Fan Clash of the Wolves Grass: A Nation's Battle for Life
运行原生查询
要运行Hibernate ORM 扩展当前不支持的MongoDB查询,您可以将查询作为MongoDB查询语言 (MQL)声明传递给 createNativeQuery() 方法。
自定义查询筛选器
本节介绍如何使用操作符创建以下类型的查询筛选器:
提示
本节并未介绍所有可用的查询操作符。要查看查询操作符的完整列表,请参阅 Hibernate ORM 查询指南中的操作符表达式。
使用比较过滤器
您可以在查询声明中使用以下操作符字段值与指定的查询值进行比较:
=:等值匹配<>:不等式匹配>:大于比较>=:大于或等于比较<:小于比较<=:小于或等于比较
The following example retrieves documents that have a year value greater than or equal to 2015 from the sample_mflix.movies collection:
var comparisonResult = session.createQuery("from Movie where year >= :y", Movie.class) .setParameter("y", 2015) .getResultList(); for (var m : comparisonResult) { System.out.println("Title: " + m.getTitle()); }
Title: Jurassic World Title: The Stanford Prison Experiment Title: Ex Machina Title: Ant-Man Title: The Danish Girl Title: The Wedding Ringer Title: Good Ol' Boy Title: A Tale of Love and Darkness Title: Aloha ...
var comparisonResult = entityManager.createQuery("select m from Movie m where m.year >= :y", Movie.class) .setParameter("y", 2015) .getResultList(); for (var m : comparisonResult) { System.out.println("Title: " + m.getTitle()); }
Title: Jurassic World Title: The Stanford Prison Experiment Title: Ex Machina Title: Ant-Man Title: The Danish Girl Title: The Wedding Ringer Title: Good Ol' Boy Title: A Tale of Love and Darkness Title: Aloha ...
使用逻辑筛选器
您可以在查询语句中使用以下操作符来组合多个查询条件:
and:匹配所有条件or:匹配任何条件not: Invert criteria
The following example retrieves a document that has a title value of "The Godfather" and a year value of 1972 from the sample_mflix.movies collection:
var logicalResult = session.createQuery("from Movie where title = :t and year = :y", Movie.class) .setParameter("t", "The Godfather") .setParameter("y", 1972) .getSingleResult(); System.out.println("Title: " + logicalResult.getTitle());
Title: The Godfather
var logicalResult = entityManager.createQuery("select m from Movie m where m.title = :t and m.year = :y", Movie.class) .setParameter("t", "The Godfather") .setParameter("y", 1972) .getSingleResult(); System.out.println("Title: " + logicalResult.getTitle());
Title: The Godfather
修改查询结果
本节介绍如何通过以下方式修改查询结果:
对结果进行排序
您可以在查询声明中使用 order by 子句,按指定字段的值对查询结果进行排序。默认下,order by 子句按升序对文档进行排序。要按降序对文档进行排序,请将 desc 关键字附加到字段名称。
The following example retrieves matching documents from the sample_mflix.movies collection and sorts them by the year field in descending order:
var sortResult = session.createQuery("from Movie where title = :t order by year desc", Movie.class) .setParameter("t", "Cinderella") .getResultList(); for (var m : sortResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Cinderella, Year: 2015 Title: Cinderella, Year: 1997 Title: Cinderella, Year: 1950
var sortResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc", Movie.class) .setParameter("t", "Cinderella") .getResultList(); for (var m : sortResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Cinderella, Year: 2015 Title: Cinderella, Year: 1997 Title: Cinderella, Year: 1950
跳过结果
您可以通过将 setFirstResult() 方法链接到查询来跳过查询结果中指定数量的文档。将要跳过的初始文档数作为参数传递给此方法。
The following example runs the same query as the preceding example but skips the first matching document in the results:
var skipResult = session.createQuery("from Movie where title = :t order by year desc", Movie.class) .setParameter("t", "Cinderella") .setFirstResult(1) .getResultList(); for (var m : skipResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Cinderella, Year: 1997 Title: Cinderella, Year: 1950
var skipResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc", Movie.class) .setParameter("t", "Cinderella") .setFirstResult(1) .getResultList(); for (var m : skipResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Cinderella, Year: 1997 Title: Cinderella, Year: 1950
限制结果
您可以通过将 setMaxResults() 方法链接到查询来限制查询返回的文档数量。将要返回的最大文档数作为参数传递给此方法。
The following example runs the same query as the sort example but returns up to two matching documents in the results:
var limitResult = session.createQuery("from Movie where title = :t order by year desc", Movie.class) .setParameter("t", "Cinderella") .setMaxResults(2) .getResultList(); for (var m : limitResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Cinderella, Year: 2015 Title: Cinderella, Year: 1997
var limitResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc", Movie.class) .setParameter("t", "Cinderella") .setMaxResults(2) .getResultList(); for (var m : limitResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear()); }
Title: Cinderella, Year: 2015 Title: Cinderella, Year: 1997
或者,可以在 HQL 或 JPQL声明中使用 limit 子句来限制查询返回的文档数量,如以下代码所示:
var limitClauseResult = session.createQuery("from Movie where title = :t order by year desc limit 2", Movie.class) .setParameter("t", "Cinderella") .getResultList();
var limitClauseResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc limit 2", Movie.class) .setParameter("t", "Cinderella") .getResultList();
高级字段查询
本节介绍如何对以下字段运行查询:
查询主键字段
要根据 ObjectId 值检索文档,如果使用会话,可以将此值作为参数传递给 get() 方法;如果使用实体经理,则可以将此值作为参数传递给 find() 方法。
The following example retrieves a document from the sample_mflix.movies collection by its ObjectId value:
var movieById = session.get(Movie.class, new ObjectId("573a13a8f29313caabd1d53c"));
var movieById = entityManager.find(Movie.class, new ObjectId("573a13a8f29313caabd1d53c"));
查询嵌入式字段
您可以通过创建 @Struct 聚合可嵌入对象来表示MongoDB嵌入式文档。您无法对单个可嵌入值创建查询筛选条件,但可以使用 Hibernate ORM 扩展来获取与特定父实体关联的 @Struct 聚合可嵌入值。
提示
要学习;了解有关表示嵌入式文档的更多信息,请参阅创建实体指南中的嵌入式数据。
The following example retrieves documents that have a title value of "Hairspray" from the sample_mflix.movies collection. Then, the code fetches the awards field, which stores the Awards @Struct aggregate embeddable, and prints the wins field of the Awards embeddable type:
var embeddedResult = session.createQuery("select awards from Movie where title = :title", Awards.class) .setParameter("title", "Hairspray") .getResultList(); for (var a : embeddedResult) { System.out.println("Award wins: " + a.getWins()); }
Award wins: 0 Award wins: 21
var embeddedResult = entityManager.createQuery("select m.awards from Movie m where m.title = :title", Awards.class) .setParameter("title", "Hairspray") .getResultList(); for (var a : embeddedResult) { System.out.println("Award wins: " + a.getWins()); }
Award wins: 0 Award wins: 21
查询数组字段
Hibernate ORM 扩展支持以下用于查询数组字段的函数:
array_contains():匹配大量字段包含指定值的文档array_contains_nullable():匹配数组字段包含指定值(包括null值)的文档array_includes():匹配数组字段包含另一个数组值的文档array_includes_nullable():匹配大量字段包含另一个大量值(包括null值)的文档
提示
要学习;了解有关大量函数的更多信息,请参阅 Hibernate ORM 用户指南中的用于处理数组的函数。
The following example uses the array_contains() function to retrieve documents that have the value "Kathryn Hahn" in the cast array field from the sample_mflix.movies collection:
var arrayResult = session.createQuery("from Movie where array_contains(cast, :actor)", Movie.class) .setParameter("actor", "Kathryn Hahn") .getResultList(); for (var m : arrayResult) { System.out.println("Title: " + m.getTitle()); }
Title: How to Lose a Guy in 10 Days Title: The Secret Life of Walter Mitty Title: Bad Words Title: Afternoon Delight Title: The D Train
var arrayResult = entityManager.createQuery("select m from Movie m where array_contains(m.cast, :actor)", Movie.class) .setParameter("actor", "Kathryn Hahn") .getResultList(); for (var m : arrayResult) { System.out.println("Title: " + m.getTitle()); }
Title: How to Lose a Guy in 10 Days Title: The Secret Life of Walter Mitty Title: Bad Words Title: Afternoon Delight Title: The D Train
更多信息
要了解有关对MongoDB数据执行其他操作的更多信息,请参阅CRUD 操作指南。
要学习;了解有关使用 HQL 和 JPQL运行查询的更多信息,请参阅 Hibernate ORM 文档中的 Hibernate 查询语言指南。