Docs 菜单
Docs 主页
/ /

指定查询

在本指南中,您可以学习;了解如何使用MongoDB Extension for Hibernate ORM 来指定数据库查询。

您可以通过创建查询过滤来优化查询返回的文档设立。查询过滤是一个表达式,用于指定MongoDB在读取或写入操作中用于匹配文档的搜索条件。要创建MongoDB查询筛选器,请使用 Hibernate Query Language (HQL) 或 Jakarta Persistence Query Language (JPQL) 语句。

提示

要学习;了解有关 HQL 和 JPQL 语法的详情,请参阅 Hibernate ORM 文档中的 Hibernate 查询语言指南 。

注意

查询支持

MongoDB Extension for Hibernate ORM 不支持所有MongoDB和 Hibernate查询功能。要学习;了解详情,请参阅“功能兼容性”页面上的 查询支持。

本指南中的示例使用Movie 实体,它表示Atlas示例数据集中的sample_mflix.movies 集合。Movie 实体具有以下定义:

import com.mongodb.hibernate.annotations.ObjectIdGenerator;
import org.bson.types.ObjectId;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "movies")
public class Movie {
@Id
@ObjectIdGenerator
private ObjectId id;
private String title;
private String plot;
private int year;
private String[] cast;
public Movie(String title, String plot, int year, 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 String[] getCast() {
return cast;
}
public void setCast(String[] cast) {
this.cast = cast;
}
}

要学习;了解如何创建使用MongoDB Extension for Hibernate ORM 与此MongoDB示例集合交互的Java应用程序,请参阅入门教程。

重要

持久性上下文

启用Hibernate ORM 能够与数据库交互,您必须使用 Hibernate Session 或 Jakarta Persistence EntityManager 在持久性上下文中运行操作。使用 HQL 定义会话查询,使用 JPQL 定义实体管理器查询。

在运行本指南中的示例之前,请确保将持久性上下文和ACID 事务管理代码添加到应用程序中,代码类似于以下代码:

var sf = HibernateUtil.getSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
// ... Perform CRUD operations here
tx.commit();
session.close();
sf.close();

要使用会话,您必须创建一个配置HibernateUtil.javaSessionFactory 文件。要学习;了解更多信息,请参阅入门教程中的配置应用程序步骤。

// 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() 方法。在此声明中,指定表示要查询的集合的实体。

以下示例通过查询 Movie 实体从 sample_mflix.movies集合中检索所有文档的 title 值:

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() 方法。在此声明中,指定表示要查询的集合的实体以及匹配条件。

以下示例从 sample_mflix.movies集合中检索 title 值为 "Romeo and Juliet" 的文档:

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

要检索匹配特定条件的单个文档,请将 getSingleResult() 方法链接到 createQuery() 方法。

以下示例从 sample_mflix.movies集合中检索 title 值为 "Best in Show" 的单个文档:

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

重要

NonUniqueResultException 错误

如果查询匹配多个文档,则getSingleResult() 方法会引发NonUniqueResultException 错误。要避免此错误,请确保查询仅匹配一个文档或将查询结果限制为一个文档。

您可以使用 Jakarta Persistence Criteria API以编程方式构建类型安全的查询,而不是使用 HQL 或 JPQL 语句创建查询筛选器。

要使用 Criteria API创建查询,请执行以下操作:

  1. 从会话或实体管理器创建 CriteriaBuilder对象。

  2. 从构建器创建一个 CriteriaQuery对象,并指定要查询的实体。

  3. 使用 CriteriaQuery 类提供的查询方法来指定查询条件。

提示

要学习;了解有关 Criteria API 的更多信息,请参阅 Jakarta EE 文档中的使用 Criteria API创建查询。

以下示例使用 Criteria API从 sample_mflix.movies集合中检索year 值为 1925 的所有文档:

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查询指南中的操作符表达式。

注意

Hibernate ORM 扩展不支持所有比较操作符,包括LIKEBETWEEN 。要学习;了解有关支持限制的更多信息,请参阅“功能兼容性”页面上的“查询支持”。

您可以在查询语句中使用以下操作符将字段值与指定的查询值进行比较:

  • =:等值匹配

  • <>:不等式匹配

  • >:大于比较

  • >=:大于或等于比较

  • <:小于比较

  • <=:小于或等于比较

以下示例从 sample_mflix.movies集合中检索 year 值大于或等于 2015 的文档:

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

以下示例从 sample_mflix.movies集合中检索 title 值为 "The Godfather"year 值为 1972 的文档:

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 关键字附加到字段名称。

以下示例从 sample_mflix.movies集合中检索匹配的文档,并按 year字段降序对它们进行排序:

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() 方法链接到查询来跳过查询结果中指定数量的文档。将要跳过的初始文档数作为参数传递给此方法。

以下示例运行与前面的示例相同的查询,但跳过结果中的第一个匹配文档:

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() 方法链接到查询来限制查询返回的文档数量。将要返回的最大文档数作为参数传递给此方法。

以下示例运行与排序示例相同的查询,但在结果中最多返回两个匹配的文档:

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() 方法。

以下示例通过文档的 ObjectId 值从 sample_mflix.movies集合中检索文档:

var movieById = session.get(Movie.class, new ObjectId("573a13a8f29313caabd1d53c"));
var movieById = entityManager.find(Movie.class, new ObjectId("573a13a8f29313caabd1d53c"));

您可以通过创建 @Struct 聚合可嵌入对象来表示MongoDB嵌入式文档。您无法对单个可嵌入值创建查询筛选器,但可以使用 Hibernate ORM 扩展来获取与特定父实体关联的 @Struct 聚合可嵌入值。

提示

要学习;了解有关表示嵌入式文档的更多信息,请参阅创建实体指南中的嵌入式数据。

重要

查询限制

要学习;了解有关嵌入式查询限制的更多信息,请参阅“功能兼容性”页面上的 Hibernate 查询支持。

以下示例从 sample_mflix.movies集合中检索 title 值为 "Hairspray" 的文档。然后,代码获取存储 Awards @Struct 聚合可嵌入类型的 awards字段,并打印 Awards 可嵌入类型的 wins字段:

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 用户指南中的用于处理数组的函数。

以下示例使用 array_contains() 函数检索sample_mflix.movies集合中 cast大量字段的值为 "Kathryn Hahn" 的文档:

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数据执行其他操作的更多信息,请参阅执行增删改查操作指南。

要学习;了解有关使用 HQL 和 JPQL运行查询的更多信息,请参阅 Hibernate ORM 文档中的 Hibernate 查询语言指南。

后退

增删改查操作

在此页面上