对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

指定查询

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

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

提示

要了解有关 HQL 和 JPQL 语法的更多信息,请参阅 Hibernate ORM 文档中的Hibernate 查询语言指南。

注意

查询支持

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

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.time.Instant;
import java.util.List;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
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 List<String> cast;
private List<String> directors;
private Instant released;
@Embedded
private Awards awards;
@OneToMany(mappedBy = "movie", fetch = FetchType.LAZY)
private List<Comment> comments;
public Movie(String title, String plot, int year, List<String> cast, List<String> directors, Instant released, Awards awards) {
this.title = title;
this.plot = plot;
this.year = year;
this.cast = cast;
this.directors = directors;
this.released = released;
this.awards = awards;
}
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;
}
public List<String> getDirectors() {
return directors;
}
public void setDirectors(List<String> directors) {
this.directors = directors;
}
public Awards getAwards() {
return awards;
}
public void setAwards(Awards awards) {
this.awards = awards;
}
public Instant getReleased() {
return released;
}
public void setReleased(Instant released) {
this.released = released;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
}

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

本页上的代码示例还使用了以下 Awards @Struct 聚合可嵌入对象:

@Embeddable
@Struct(name = "Awards")
public class Awards {
private int wins;
private int nominations;
private String text;
public Awards(int wins, int nominations, String text) {
this.wins = wins;
this.nominations = nominations;
this.text = text;
}
public Awards() {
}
public int getWins() {
return wins;
}
public void setWins(int wins) {
this.wins = wins;
}
public int getNominations() {
return nominations;
}
public void setNominations(int nominations) {
this.nominations = nominations;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}

重要

持久性上下文

启用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:

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

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

在创建 SessionFactory 实例之前,必须将 com.mongodb.hibernate.semantics.nulls 配置属性设置为 MQL。此属性为必填项,没有默认值,且目前不接受其他值。如果省略该属性或将其设置为其他值,Hibernate ORM 扩展将抛出 HibernateException。

当您将 com.mongodb.hibernate.semantics.nulls 设置为 MQL 时,该属性声明与 null 相关的行为遵循 Hibernate ORM 扩展在转换过程中生成的 MongoDB 查询语言 (MQL),而不是 SQL null 语义定义的三值逻辑。

由于 Hibernate ORM 扩展不提供特定的 ACID 一致性保证,因此与 null 相关的行为结果可能会在不同版本之间发生变化。

以下示例在您的 hibernate.properties 文件中设置 com.mongodb.hibernate.semantics.nulls 属性:

com.mongodb.hibernate.semantics.nulls=MQL

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

  • =:等值匹配

  • <>:不等式匹配

  • >:大于比较

  • >=:大于或等于比较

  • <:小于比较

  • <=:小于或等于比较

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());
}

行值谓词在单个表达式中将带括号的字段列表与带括号的值列表进行比较。Hibernate ORM 扩展支持使用以下操作符的行值谓词:

  • =:等值匹配

  • <>:不等式匹配

  • IN 以及 NOT IN:匹配值行列表

您可以将值作为绑定参数或字面量提供,并且每个列表必须包含相同数量的组件。

以下示例从 sample_mflix.movies 集合中检索 title 值为 "Jurassic World" 且 year 值为 2015 的文档:

var rowValueResult = session.createQuery("from Movie where (title, year) = (:t, :y)", Movie.class)
.setParameter("t", "Jurassic World")
.setParameter("y", 2015)
.getResultList();
for (var m : rowValueResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展会分别比较每对组件。前面的行值谓词会转换为以下 $match 阶段:

{
"$match": {
"$and": [
{ "title": { "$eq": "Jurassic World" } },
{ "year": { "$eq": 2015 } }
]
}
}

使用 <> 操作符的行值谓词会转换为包裹在 $nor 表达式中的相同 $and 表达式。

如果将字段与另一个字段列表进行比较(如 where (title1, year1) = (title2, year2) 所示),Hibernate ORM 扩展会将谓词转换为 $expr 表达式。

您可以在 SELECT 子句中使用行值谓词。该谓词在投影中计算为布尔值。

注意

空值语义

Row-value predicates follow MongoDB Query Language null semantics rather than Hibernate ORM ternary logic, so a <> predicate matches documents in which a component is null or missing. To learn more, see the Compare Field Values to Null section of this guide.

要将一行字段与多行值进行匹配,请使用 IN 操作符。以下示例检索匹配两个 title 和 year 对中的任一个的文档:

var rowValueInResult = session.createQuery(
"from Movie where (title, year) in (('Jurassic World', 2015), ('Ex Machina', 2015))", Movie.class)
.getResultList();
for (var m : rowValueInResult) {
System.out.println("Title: " + m.getTitle());
}

上述行值谓词转换为以下 $match 阶段:

{
"$match": {
"$or": [
{ "$and": [
{ "title": { "$eq": "Jurassic World" } },
{ "year": { "$eq": 2015 } }
] },
{ "$and": [
{ "title": { "$eq": "Ex Machina" } },
{ "year": { "$eq": 2015 } }
] }
]
}
}

如果列表仅包含一行值,则谓词仅转换为 $and 表达式。NOT IN 谓词转换为包装在 $nor 表达式中的 $or 表达式。

重要

排序比较

Hibernate ORM 扩展不支持使用 >、>=、< 或 <= 操作符的行值谓词。这些谓词会导致 Hibernate ORM 扩展抛出 FeatureNotSupportedException。

当您使用比较操作符将字段与 null 进行比较时,Hibernate ORM 扩展会应用 MongoDB 查询语言的 null 语义,而不是 Hibernate ORM 定义的三元逻辑。

注意

针对 null 的 Hibernate 三值逻辑

Hibernate ORM v6.3 及更高版本将与 null 的比较评估为 null,谓词将其视为 false。Hibernate ORM 扩展未实现此行为。要了解有关 Hibernate ORM 扩展支持哪些功能的更多信息,请参阅“功能兼容性”页面上的数据类型支持。

MongoDB 比较操作符将缺失字段和存储明确 null 值的字段都视为 null。因此,= null 比较匹配字段存储 null 的文档和字段不存在的文档。<> null 或 != null 比较匹配字段存储任何其他值的文档。

以下示例使用 = 操作符从 sample_mflix.movies 集合中检索具有 null 或缺少 cast 值的文档:

var nullComparisonResult = session.createQuery("from Movie where cast = null", Movie.class)
.getResultList();
for (var m : nullComparisonResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将此查询转换为以下 $match 阶段:

{
"$match": {
"cast": { "$eq": null }
}
}

Comparisons that use the >, >=, <, and <= operators follow the MongoDB BSON comparison order for non-existent fields. Because null is its own BSON type, A >= null or <= null comparison matches documents in which the field stores null or is missing. A > null or < null comparison matches no documents.

To match null and missing values by using a predicate instead of a comparison operator, see the IS NULL and IS NOT NULL sections of this guide.

您可以根据字段值、字面量和查询参数计算值。然后,您可以在 SELECT 子句中返回该值,或在 WHERE 子句中对其进行比较。Hibernate ORM 扩展将计算表达式转换为 MongoDB 聚合表达式。

Hibernate ORM 扩展在计算表达式中支持以下算术操作符:

  • +:加法,转换为 $add

  • -:减法,转换为 $subtract

  • *: 乘法,即 $multiply

  • /: Division,翻译为 $divide

  • 一元 - 和 +

注意

除法总是返回整数

Hibernate ORM 将 MongoDB 聚合管道中的除法转换为 MongoDB $divide 操作符,该操作符始终返回 double。Hibernate ORM 扩展通过将 $divide 包装在 $toInt 中来截断结果,如果结果类型为 BIGINT,则包装在 $toLong 中。此行为应用到 / 操作符和 Criteria API quot() 方法,无论您是否启用 Hibernate ORM PORTABLE_INTEGER_DIVISION 设置。

不支持 div 操作符。

You can also use the comparison operators described in the Use Comparison Operators section within computed expressions.

重要

操作数限制

计算表达式的操作数必须是字段引用、字面量或查询参数。Hibernate ORM 扩展不支持将函数调用作为操作数。

由于 Hibernate ORM 将 HQL % 操作符重写为 mod() 函数调用,因此 % 也不受支持。要执行取模运算,请使用 Criteria API CriteriaBuilder.mod() 方法,该方法会转换为 MongoDB $mod 操作符。

Criteria API 的 CriteriaBuilder.quot() 方法的行为与 / 操作符相同。

当您选择计算表达式时,Hibernate ORM 扩展会将计算值添加到 $project 阶段。如果您使用 AS 关键字为表达式分配别名,Hibernate ORM 扩展将使用该别名作为投影键。否则,它会生成一个格式为 #c_<n> 的键。

以下示例通过从查询参数中减去 year 字段值,计算 sample_mflix.movies 集合中每部 "Hairspray" 电影的年龄:

var arithmeticResult = session.createQuery(
"select title, :currentYear - year as age from Movie where title = :title",
Object[].class)
.setParameter("currentYear", 2026)
.setParameter("title", "Hairspray")
.getResultList();
for (var row : arithmeticResult) {
System.out.println("Title: " + row[0] + ", Age: " + row[1]);
}

Hibernate ORM 扩展将上述计算表达式转换为以下 $project 阶段:

{
"$project": {
"title": true,
"age": { "$subtract": [ 2026, "$year" ] },
"_id": 0
}
}

In the WHERE clause, you can compare a computed expression to a value or compare two field values to each other. When either side of a comparison is not a direct field reference or value, the Hibernate ORM extension wraps the comparison in the MongoDB $expr operator. Comparisons between a field and a value continue to use the compact { field: { operator: value } } form.

以下示例检索了在 2026 之前不到 20 年发行的 "Hairspray" 部电影:

var computedFilterResult = session.createQuery(
"from Movie where title = :title and :currentYear - year < 20", Movie.class)
.setParameter("title", "Hairspray")
.setParameter("currentYear", 2026)
.getResultList();
for (var m : computedFilterResult) {
System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());
}

Hibernate ORM 扩展将上述查询转换为以下 $match 阶段,其中 title 比较使用紧凑形式,而计算比较使用 $expr:

{
"$match": {
"$and": [
{ "title": { "$eq": "Hairspray" } },
{ "$expr": { "$lt": [ { "$subtract": [ 2026, "$year" ] }, 20 ] } }
]
}
}

您可以在 SELECT 声明中使用比较来返回其布尔值结果,而不是将比较用作过滤器。

以下示例返回每部 "Hairspray" 电影的标题以及该电影是否在 2000 之后发行:

var comparisonResult = session.createQuery(
"select title, year > 2000 as isRecent from Movie where title = :title",
Object[].class)
.setParameter("title", "Hairspray")
.getResultList();
for (var row : comparisonResult) {
System.out.println("Title: " + row[0] + ", Recent: " + row[1]);
}

Hibernate ORM 扩展将前面的比较转换为以下 $project 阶段:

{
"$project": {
"title": true,
"isRecent": { "$gt": [ "$year", 2000 ] },
"_id": 0
}
}

CASE 表达式为您指定的每个条件返回不同的值。Hibernate ORM 扩展支持 HQL 和 JPQL 简单和搜索的 CASE 表达式:

  • 简单 case:将 CASE 关键字后的表达式与每个 WHEN 子句中的值进行相等性比较。简单 case 表达式的一个示例是 case year when 2000 then 'Modern' else 'Classic' end。

  • 搜索案例:每个 WHEN 子句都指定一个谓词。搜索案例表达式的示例是 case when year > 2000 then 'Modern' else 'Classic' end。

The Hibernate ORM extension translates a CASE expression to the MongoDB $switch operator, which creates a branch for each WHEN clause and evaluates the branches in the order that you specify them. The ELSE clause becomes the default value of $switch. If you omit the ELSE clause, the expression returns null when no branch matches.

CASE 表达式可以返回计算出的表达式,您可以在以下位置使用 CASE 表达式:

  • SELECT 子句,如下示例所示。

  • WHERE 子句中比较的操作数,Hibernate ORM 扩展将其包装在 MongoDB $expr 操作符中。

  • 批量更新声明的 SET 子句。要查看示例,请参阅《执行 CRUD 操作》指南中的“基于条件逻辑更新多个示例”部分。

以下示例返回每部 "Hairspray" 电影的标题以及一个取决于电影 year 值的标签:

var caseResult = session.createQuery(
"select title, case when year > 2000 then 'Modern' else 'Classic' end as era "
+ "from Movie where title = :title",
Object[].class)
.setParameter("title", "Hairspray")
.getResultList();
for (var row : caseResult) {
System.out.println("Title: " + row[0] + ", Era: " + row[1]);
}

Hibernate ORM 扩展将前面的 CASE 表达式转换为以下 $project 阶段:

{
"$project": {
"title": true,
"era": {
"$switch": {
"branches": [
{ "case": { "$gt": [ "$year", 2000 ] }, "then": "Modern" }
],
"default": "Classic"
}
},
"_id": 0
}
}

重要

CASE 表达式限制

因为 CASE 表达式会生成 MongoDB 聚合表达式,所以不能在需要字段引用或字面值的位置使用它。如果您使用 CASE 表达式,Hibernate ORM 扩展会引发 FeatureNotSupportedException:

  • 在 ORDER BY 子句中,除非相同的 CASE 表达式是 GROUP BY 键。

  • 作为 LIKE 谓词的匹配表达式。

  • 作为 IN 或 IS NULL 谓词的测试表达式。

  • 作为 WHERE 子句谓词,而不是其操作数。

Hibernate ORM 扩展在您的查询声明中支持以下谓词比较操作符:

注意

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

EXISTS 谓词匹配具有特定字段的文档,并且对于每个匹配的父文档仅返回一个结果,无论有多少数组元素匹配。

注意

EXISTS 子查询限制

Hibernate ORM 扩展仅支持对父实体的数组字段使用 EXISTS 子查询,且仅支持在 WHERE 子句中使用。Hibernate ORM 扩展不支持以下 EXISTS 子查询:

  • 在未先指定字段的情况下对实体进行查询

  • 比较同一父文档中的字段

  • 出现在 SELECT 子句中

For a full example, see the Query on Elements of an Embedded Array section of this guide.

BETWEEN 谓词匹配字段值在指定范围内的文档。

以下示例使用 BETWEEN 谓词,从 sample_mflix.movies 集合中检索具有 year 值在 2012 和 2013 之间(包含边界)的文档:

var betweenResult = session.createQuery("from Movie where year between :start and :end", Movie.class)
.setParameter("start", 2012)
.setParameter("end", 2013)
.getResultList();
for (var m : betweenResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 BETWEEN 谓词转换为以下 $match 阶段:

{
"$match": {
"year": { "$gte": 2012, "$lte": 2013 }
}
}

IN 谓词匹配字段值等于指定列表中任何值的文档。您可以将列表值作为字面量、命名参数或位置参数提供。

以下示例使用 IN 谓词从 sample_mflix.movies 集合中检索 year 值为 1994 或 1996 的文档:

var inResult = session.createQuery("from Movie where year in (:first, :second)", Movie.class)
.setParameter("first", 1994)
.setParameter("second", 1996)
.getResultList();
for (var m : inResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 IN 谓词转换为以下 $match 阶段:

{
"$match": {
"year": { "$in": [ 1994, 1996 ] }
}
}

空列表是有效的,但是它不会匹配任何文档。示例,year in () 不匹配任何文档。

注意

IN 谓词限制

仅当 IN 左侧的值为字段路径(Field Path)时,Hibernate ORM 扩展才支持 IN 谓词。Hibernate ORM 扩展不支持以下 IN 谓词:

  • 将子查询作为值列表。

  • 针对数组值表达式测试值,如 :value in m.cast 中所示。要将值与数组字段进行匹配,请改用 array_contains() 函数。

To learn more about querying an array, see the Query an Array Field section of this guide.

NOT IN 谓词匹配字段值不等于指定列表中任何值的文档。NOT IN 接受与 IN 谓词相同的列表形式,并具有相同的限制。

以下示例使用 NOT IN 谓词从 sample_mflix.movies 集合中检索 title 值不是 "Romeo and Juliet" 或 "Best in Show" 的文档。由于 NOT IN 仅排除列出的值,因此该示例调用 setMaxResults() 方法将结果集限制为十个文档:

var notInResult = session.createQuery("from Movie where title not in (:first, :second)", Movie.class)
.setParameter("first", "Romeo and Juliet")
.setParameter("second", "Best in Show")
.setMaxResults(10)
.getResultList();
for (var m : notInResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 NOT IN 谓词转换为以下 $match 阶段:

{
"$match": {
"title": { "$nin": [ "Romeo and Juliet", "Best in Show" ] }
}
}

由于 $nin 将每个文档与空值列表进行匹配,title not in () 匹配所有文档。

注意

NOT IN 限制

仅当 NOT IN 左侧的值为字段路径(Field Path)时,Hibernate ORM 扩展才支持 NOT IN 谓词。Hibernate ORM 扩展不支持以下 NOT IN 谓词:

  • 将子查询作为值列表。

  • 检查一个值是否符合数组值表达式,如 :value not in m.cast 所示。

注意

空值语义

Row-value predicates follow MongoDB Query Language null semantics rather than Hibernate ORM ternary logic, so a NOT IN predicate matches documents in which a component is null or missing. To learn more, see the Compare Field Values to Null section of this guide.

IS NULL 谓词匹配具有 null 或缺失值的特定字段的文档。

To compare a field to null by using a comparison operator instead of a predicate, see the Compare Field Values to Null section of this guide.

以下示例使用 IS NULL 谓词从 sample_mflix.movies 集合中检索具有缺失或 null cast 值的文档:

var isNullResult = session.createQuery("from Movie where cast is null", Movie.class)
.getResultList();
for (var m : isNullResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 IS NULL 条件转换为以下 $match 阶段,该阶段匹配字段明确为 null 或不存在的文档:

{
"$match": {
"cast": { "$eq": null }
}
}

IS NOT NULL 谓词匹配具有非空或非缺失值的字段的文档。

以下示例使用 IS NOT NULL 谓词从 sample_mflix.movies 集合中检索具有 directors 值的文档:

var isNotNullResult = session.createQuery("from Movie where directors is not null", Movie.class)
.getResultList();
for (var m : isNotNullResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将上述 IS NOT NULL 谓词转译为以下 $match 阶段,该阶段匹配字段存在且未明确 null 的文档:

{
"$match": {
"directors": { "$ne": null }
}
}

LIKE条件区分大小写,并匹配字段值与指定模式匹配的文档。模式与字段的整个值进行匹配,并可以使用以下通配符:

  • %:匹配零个或多个字符。

  • _: 匹配恰好一个字符。

要匹配前缀,请在模式末尾包含 %;要匹配后缀,请在模式开头包含 %。

提示

转义通配符

如果要将 % 或 _ 作为字面字符进行匹配,请使用 ESCAPE 子句。示例,title like '100!%' escape '!' 匹配值 "100%"。您可以将 ESCAPE 与 %、_ 或逃逸字符本身一起使用。如果您将其与任何其他字符一起使用,或将其留在模式末尾,Hibernate ORM 扩展将抛出 IllegalArgumentException 。

以下示例使用 LIKE 谓词从 sample_mflix.movies 集合中检索 title 值以 "W" 开头,后跟任何单个字符,然后是 "r" 的文档:

var likeResult = session.createQuery("from Movie where title like 'W_r%'", Movie.class)
.getResultList();
for (var m : likeResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 LIKE 谓词转换为以下 $match 阶段:

{
"$match": {
"title": { "$regex": /^W.r.*$/s }
}
}

注意

LIKE 谓词限制

与 LIKE 进行比较的值必须是 string 字面量,例如 '%War%'。Hibernate ORM 扩展不支持模式的绑定参数 (like :pattern)、另一个字段 (like m.plot) 或计算值 (like concat('War', '%')),如果使用其中任何一个,则会抛出 FeatureNotSupportedException。

要了解有关 HQL LIKE 谓词的更多信息,请参阅 Hibernate ORM 文档中的Hibernate 查询语言指南。

The NOT LIKE predicate matches documents in which a field value does not match the specified pattern. The Hibernate ORM extension negates the $regex filter that the LIKE predicate produces and uses the same pattern-matching behavior and restrictions as the LIKE predicate.

以下示例使用 NOT LIKE 谓词从 sample_mflix.movies 集合中检索具有 title 值且不以 "The" 开头的文档。由于谓词与大多数文档匹配,示例调用 setMaxResults() 方法将结果集限制为五个文档:

var notLikeResult = session.createQuery("from Movie where title not like 'The%'", Movie.class)
.setMaxResults(5)
.getResultList();
for (var m : notLikeResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 NOT LIKE 谓词转换为以下 $match 阶段:

{
"$match": {
"$nor": [
{ "title": { "$regex": /^The.*$/s } }
]
}
}

The ILIKE predicate is the case-insensitive form of the LIKE predicate. The Hibernate ORM extension marks the $regex filter that the LIKE predicate produces as case-insensitive and uses the same pattern-matching behavior and restrictions as the LIKE predicate.

以下示例使用 ILIKE 谓词从 sample_mflix.movies 集合中检索 title 值包含 "Star" 的文档:

var ilikeResult = session.createQuery("from Movie where title ilike '%Star%'", Movie.class)
.getResultList();
for (var m : ilikeResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 ILIKE 谓词转换为以下 $match 阶段:

{
"$match": {
"title": { "$regex": /^.*Star.*$/is }
}
}

The NOT ILIKE predicate is the case-insensitive form of the NOT LIKE predicate. The Hibernate ORM extension negates the case-insensitive $regex filter that the ILIKE predicate produces and uses the same pattern-matching behavior and restrictions as the LIKE predicate.

以下示例使用 NOT ILIKE 谓词从 sample_mflix.movies 集合中检索 title 值不包含 "The" 的文档。由于谓词匹配大多数文档,因此该示例调用 setMaxResults() 方法将结果集限制为五个文档:

var notIlikeResult = session.createQuery("from Movie where title not ilike '%The%'", Movie.class)
.setMaxResults(5)
.getResultList();
for (var m : notIlikeResult) {
System.out.println("Title: " + m.getTitle());
}

Hibernate ORM 扩展将前面的 NOT ILIKE 谓词转换为以下 $match 阶段:

{
"$match": {
"$nor": [
{ "title": { "$regex": /^.*The.*$/is } }
]
}
}

您可以在查询声明中使用以下操作符来组合多个查询条件:

  • and:匹配所有条件

  • or:匹配任何条件

  • not: 不符合匹配条件

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());

要根据 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"));

您可以通过创建 @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());
}

您可以在 HQL 或 JPQL 查询的 SELECT、WHERE、ORDER BY 和 UPDATE 子句中使用点号路径表达式来引用可嵌入类型上的字段。您还可以在路径表达式中链接多个可嵌入名称,以引用嵌套在另一个可嵌入对象中的可嵌入对象上的字段。

重要

查询限制

路径表达式不支持使用 @ColumnTransformer 注解来定义自定义读取表达式的可嵌入字段。

Hibernate ORM 扩展在构建实体模型时也会拒绝以下 @Struct 聚合可嵌入映射:

  • 用作 @Id 字段的 @Struct 聚合可嵌入对象

  • 多态 @Struct 聚合可嵌入层次结构

您不能使用路径表达式来引用这些类型上的字段。

以下示例使用路径表达式来过滤器 sample_mflix.movies 集合中的文档。sample_mflix.movies 集合中有两部 "Hairspray" 电影。一部 "Hairspray" 电影来自 1998,另一部来自 2007。该查询匹配 title 值为 "Hairspray" 且 awards.wins 值大于 10 的文档:

var matchingDocument = session.createQuery("from Movie where title = :title and awards.wins > :minWins", Movie.class)
.setParameter("title", "Hairspray")
.setParameter("minWins", 10)
.getResultList();
for (var m : matchingDocument) {
System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());
}

When a field of your entity stores an array of @Struct aggregate embeddables, you can use an EXISTS subquery to match parent documents in which at least one element of that array meets your criteria. The Hibernate ORM extension translates the subquery to the MongoDB $elemMatch operator, which applies all criteria to the same array element.

注意

在本节中使用 sample_restaurants 数据库

本节中的示例使用 sample_restaurants.restaurants 集合,而不是本指南其他部分中使用的 sample_mflix.movies 集合。

To run these examples, connect to the sample_restaurants database in your connection string. To learn more about the sample_restaurants database, see the Atlas sample datasets.

以下 Restaurant 实体映射到 restaurants 集合,并在其 grades 字段中存储 Grade 可嵌入对象的列表:

package org.example;
import com.mongodb.hibernate.annotations.ObjectIdGenerator;
import jakarta.persistence.Column;
import org.bson.types.ObjectId;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "restaurants")
public class Restaurant {
@Id
@ObjectIdGenerator
@Column(name = "_id")
private ObjectId id;
private String name;
private String borough;
private List<Grade> grades;
public Restaurant(String name, String borough, List<Grade> grades) {
this.name = name;
this.borough = borough;
this.grades = grades;
}
public Restaurant() {
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBorough() {
return borough;
}
public void setBorough(String borough) {
this.borough = borough;
}
public List<Grade> getGrades() {
return grades;
}
public void setGrades(List<Grade> grades) {
this.grades = grades;
}
}

以下 Grade @Struct 聚合嵌入式代表 grades 数组的每个元素:

package org.example;
import jakarta.persistence.*;
import org.hibernate.annotations.Struct;
@Embeddable
@Struct(name = "Grade")
public class Grade {
private String grade;
private int score;
public Grade() {
}
public Grade(String grade, int score) {
this.grade = grade;
this.score = score;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}

提示

要了解有关可嵌入数组的更多信息,请参阅“创建实体”指南中的嵌入式数据。

restaurants 集合中的文档类似于以下内容:

{
"_id": { "$oid": "5eb3d668b31de5d588f4292a" },
"name": "Morris Park Bake Shop",
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{ "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 },
{ "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 }
]
}

以下示例检索 grades 数组元素中至少有一个 grade 值为 "B" 且 score 值等于 12 的餐厅。由于这两个条件出现在同一个子查询中,因此它们必须匹配同一个数组元素:

var existsResult = session.createQuery(
"from Restaurant r where exists (select g.grade from r.grades g where g.grade = :grade and g.score = :score)",
Restaurant.class)
.setParameter("grade", "B")
.setParameter("score", 12)
.getResultList();
for (var r : existsResult) {
System.out.println("Name: " + r.getName());
}

Hibernate ORM 扩展将前面的 EXISTS 子查询转换为以下 $match 阶段:

{
"$match": {
"grades": {
"$elemMatch": {
"grade": { "$eq": "B" },
"score": { "$eq": 12 }
}
}
}
}

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());
}

您可以在 HQL 和 JPQL 查询中使用聚合函数来对查询结果进行分组和汇总,或者使用 HAVING 子句来过滤器分组结果。HQL 和 JPQL 支持以下聚合函数:

  • count()

  • sum()

  • avg()

  • min()

  • max()

注意

GROUP BY 要求

聚合函数需要 GROUP BY 子句。使用聚合函数但不分组结果的查询(例如 select count(*) from Movie)尚不支持。在 SELECT 子句中的非聚合字段也必须出现在 GROUP BY 子句中。

以下示例按年份对 1920 到 1924 之间发行的电影进行分组。对于每一年,它都会返回电影数量和所有电影的总运行时间。HAVING 子句仅包含电影总运行时间超过 300 分钟的年份,并按年份对结果进行排序。

var aggregateResult = session.createQuery(
"select year, count(*), sum(runtime) from Movie where year between 1920 and 1924 "
+ "group by year having sum(runtime) > 300 order by year",
Object[].class)
.getResultList();
for (var row : aggregateResult) {
System.out.println("Year: " + row[0] + ", Count: " + row[1] + ", Total runtime: " + row[2]);
}

要了解有关对MongoDB数据执行其他操作的更多信息,请参阅CRUD 操作指南。

要了解如何查询通过关联连接的跨实体,请参阅 跨集合连接实体 指南。

要学习如何返回 datetime 值的一部分或将 datetime 值渲染为 string,请参阅在查询中使用日期时间函数指南。

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