查询文档

您可以使用QueryCriteria 类来表达您的查询。它们的方法名称与原生 MongoDB 运算符名称相对应,例如 ltlteis 等。QueryCriteria 类遵循流畅的 API 风格,因此您可以将多个方法条件和查询链接在一起,同时保持代码易于理解。为了提高可读性,静态导入可以让您避免使用“new”关键字来创建QueryCriteria 实例。您也可以使用BasicQuery 从普通 JSON 字符串创建Query 实例,如下例所示

示例 1. 从普通 JSON 字符串创建 Query 实例
BasicQuery query = new BasicQuery("{ age : { $lt : 50 }, accounts.balance : { $gt : 1000.00 }}");
List<Person> result = mongoTemplate.find(query, Person.class);

查询集合中的文档

之前,我们看到了如何使用MongoTemplate 上的findOnefindById 方法来检索单个文档。这些方法直接返回单个域对象,或者使用响应式 API 返回一个发出单个元素的Mono。我们还可以查询要作为域对象列表返回的文档集合。假设我们有许多Person 对象,它们的名字和年龄存储为集合中的文档,并且每个人都有一个嵌入式帐户文档,其中包含余额,那么我们现在可以使用以下代码运行查询

使用 MongoTemplate 查询文档
  • 命令式

  • 响应式

import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;

// ...

List<Person> result = template.query(Person.class)
  .matching(query(where("age").lt(50).and("accounts.balance").gt(1000.00d)))
  .all();
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;

// ...

Flux<Person> result = template.query(Person.class)
  .matching(query(where("age").lt(50).and("accounts.balance").gt(1000.00d)))
  .all();

所有查找方法都将Query 对象作为参数。此对象定义用于执行查询的条件和选项。条件是通过使用Criteria 对象指定的,该对象有一个名为where 的静态工厂方法来实例化一个新的Criteria 对象。我们建议使用org.springframework.data.mongodb.core.query.Criteria.whereQuery.query 的静态导入,以使查询更易读。

查询应返回满足指定条件的Person 对象的ListFlux。本节的其余部分列出了CriteriaQuery 类的对应于 MongoDB 中提供的运算符的方法。大多数方法返回Criteria 对象,以便为 API 提供流畅的风格。

Criteria 类的 方法

Criteria 类提供以下方法,所有这些方法都对应于 MongoDB 中的运算符

  • Criteria all (Object o) 使用$all 运算符创建条件

  • Criteria and (String key) 将具有指定key 的链式Criteria 添加到当前Criteria 中,并返回新创建的Criteria

  • Criteria andOperator (Criteria…​ criteria) 使用$and 运算符为所有提供的条件创建与查询(需要 MongoDB 2.0 或更高版本)

  • Criteria andOperator (Collection<Criteria> criteria) 使用$and 运算符为所有提供的条件创建与查询(需要 MongoDB 2.0 或更高版本)

  • Criteria elemMatch (Criteria c) 使用$elemMatch 运算符创建条件

  • Criteria exists (boolean b) 使用 $exists 运算符创建条件

  • Criteria gt (Object o) 使用 $gt 运算符创建条件

  • Criteria gte (Object o) 使用 $gte 运算符创建条件

  • Criteria in (Object…​ o) 使用 $in 运算符为可变参数创建条件。

  • Criteria in (Collection<?> collection) 使用 $in 运算符使用集合创建条件

  • Criteria is (Object o) 使用字段匹配 ({ key:value }) 创建条件。如果指定的值是文档,则文档中字段的顺序和完全相等性很重要。

  • Criteria lt (Object o) 使用 $lt 运算符创建条件

  • Criteria lte (Object o) 使用 $lte 运算符创建条件

  • Criteria mod (Number value, Number remainder) 使用 $mod 运算符创建条件

  • Criteria ne (Object o) 使用 $ne 运算符创建条件

  • Criteria nin (Object…​ o) 使用 $nin 运算符创建条件

  • Criteria norOperator (Criteria…​ criteria) 使用 $nor 运算符为所有提供的条件创建或查询

  • Criteria norOperator (Collection<Criteria> criteria) 使用 $nor 运算符为所有提供的条件创建或查询

  • Criteria not () 使用 $not 元运算符创建条件,该运算符影响紧随其后的子句

  • Criteria orOperator (Criteria…​ criteria) 使用 $or 运算符为所有提供的条件创建或查询

  • Criteria orOperator (Collection<Criteria> criteria) 使用 $or 运算符为所有提供的条件创建或查询

  • Criteria regex (String re) 使用 $regex 创建条件

  • Criteria sampleRate (double sampleRate) 使用 $sampleRate 运算符创建条件

  • Criteria size (int s) 使用 $size 运算符创建条件

  • Criteria type (int t) 使用 $type 运算符创建条件

  • Criteria matchingDocumentStructure (MongoJsonSchema schema) 使用 $jsonSchema 运算符为 JSON 架构条件 创建条件。$jsonSchema 只能应用于查询的顶层,不能应用于特定属性。使用架构的 properties 属性来匹配嵌套字段。

  • Criteria bits()MongoDB 位运算符查询 的入口,例如 $bitsAllClear

Criteria 类还为地理空间查询提供以下方法。

  • Criteria within (Circle circle) 使用 $geoWithin $center 运算符创建地理空间条件。

  • Criteria within (Box box) 使用 $geoWithin $box 操作创建地理空间条件。

  • Criteria withinSphere (Circle circle) 使用 $geoWithin $center 运算符创建地理空间条件。

  • Criteria near (Point point) 使用 $near 操作创建地理空间条件。

  • Criteria nearSphere (Point point) 使用 $nearSphere$center 操作创建地理空间条件。此功能仅适用于 MongoDB 1.7 及更高版本。

  • Criteria minDistance (double minDistance) 使用 $minDistance 操作创建地理空间条件,用于与 $near 配合使用。

  • Criteria maxDistance (double maxDistance) 使用 $maxDistance 操作创建地理空间条件,用于与 $near 配合使用。

Query 类还提供了一些其他方法,允许选择特定字段,以及限制和排序结果。

Query 类的使用方法
  • Query addCriteria (Criteria criteria) 用于向查询添加其他条件。

  • Field fields () 用于定义要包含在查询结果中的字段。

  • Query limit (int limit) 用于将返回结果的大小限制为提供的限制(用于分页)。

  • Query skip (int skip) 用于跳过结果中的指定数量的文档(用于分页)。

  • Query with (Sort sort) 用于为结果提供排序定义。

  • Query with (ScrollPosition position) 用于提供滚动位置(基于偏移量或键集的分页)以启动或恢复 Scroll

模板 API 允许直接使用结果投影,使您能够将查询映射到给定的域类型,同时将操作结果投影到另一个域类型,如下所示。

class

template.query(SWCharacter.class)
    .as(Jedi.class)

有关结果投影的更多信息,请参阅文档的 Projections 部分。

选择字段

MongoDB 支持 投影查询返回的字段。投影可以根据字段名称包含和排除字段(_id 字段始终包含,除非显式排除)。

示例 2. 选择结果字段
public class Person {

    @Id String id;
    String firstname;

    @Field("last_name")
    String lastname;

    Address address;
}

query.fields().include("lastname");              (1)

query.fields().exclude("id").include("lastname") (2)

query.fields().include("address")                (3)

query.fields().include("address.city")           (4)
1 结果将包含 _idlast_name,通过 { "last_name" : 1 }
2 结果将仅包含 last_name,通过 { "_id" : 0, "last_name" : 1 }
3 结果将包含 _id 和整个 address 对象,通过 { "address" : 1 }
4 结果将包含 _idaddress 对象,该对象仅包含 city 字段,通过 { "address.city" : 1 }

从 MongoDB 4.4 开始,您可以使用聚合表达式进行字段投影,如下所示

示例 3. 使用表达式计算结果字段
query.fields()
  .project(MongoExpression.create("'$toUpper' : '$last_name'"))         (1)
  .as("last_name");                                                     (2)

query.fields()
  .project(StringOperators.valueOf("lastname").toUpper())               (3)
  .as("last_name");

query.fields()
  .project(AggregationSpELExpression.expressionOf("toUpper(lastname)")) (4)
  .as("last_name");
1 使用原生表达式。使用的字段名称必须引用数据库文档中的字段名称。
2 将字段名称分配给要投影表达式结果的字段。结果字段名称不会映射到域模型。
3 使用 AggregationExpression。除了原生 MongoExpression 之外,字段名称将映射到域模型中使用的名称。
4 使用 SpEL 以及 AggregationExpression 来调用表达式函数。字段名称将映射到域模型中使用的名称。

@Query(fields="…") 允许在 Repository 级别使用表达式字段投影,如 MongoDB 基于 JSON 的查询方法和字段限制 中所述。

其他查询选项

MongoDB 提供了多种方法来将元信息(如注释或批次大小)应用于查询。使用 Query API 直接进行操作,有几种方法可以实现这些选项。

提示

索引提示可以通过两种方式应用,使用索引名称或其字段定义。

template.query(Person.class)
    .matching(query("...").withHint("index-to-use"));

template.query(Person.class)
    .matching(query("...").withHint("{ firstname : 1 }"));

游标批次大小

游标批次大小定义了每个响应批次中返回的文档数量。

Query query = query(where("firstname").is("luke"))
    .cursorBatchSize(100)

排序规则

在集合操作中使用排序规则,只需在您的查询或操作选项中指定一个 Collation 实例,如下面的两个示例所示

Collation collation = Collation.of("de");

Query query = new Query(Criteria.where("firstName").is("Amél"))
    .collation(collation);

List<Person> results = template.find(query, Person.class);

读取偏好

要使用的 ReadPreference 可以直接设置在要运行的 Query 对象上,如下所示。

template.find(Person.class)
    .matching(query(where(...)).withReadPreference(ReadPreference.secondary()))
    .all();
Query 实例上设置的偏好将优先于 MongoTemplate 的默认 ReadPreference

注释

查询可以添加注释,这使得它们更容易在服务器日志中查找。

template.find(Person.class)
    .matching(query(where(...)).comment("Use the force luke!"))
    .all();

查询不同值

MongoDB 提供了一个操作,可以使用查询从结果文档中获取单个字段的不同值。结果值不需要具有相同的数据类型,该功能也不限于简单类型。为了检索,实际结果类型对于转换和类型化很重要。以下示例展示了如何查询不同值

示例 4. 检索不同值
template.query(Person.class)  (1)
  .distinct("lastname")       (2)
  .all();                     (3)
1 查询 Person 集合。
2 选择 lastname 字段的不同值。字段名称根据域类型属性声明进行映射,并考虑潜在的 @Field 注释。
3 检索所有不同值作为 ObjectList(由于没有指定显式结果类型)。

将不同值检索到 ObjectCollection 中是最灵活的方式,因为它尝试确定域类型的属性值并将结果转换为所需的类型或映射 Document 结构。

有时,当所需字段的所有值都固定为特定类型时,直接获取正确类型的 Collection 会更方便,如以下示例所示

示例 5. 检索强类型不同值
template.query(Person.class)  (1)
  .distinct("lastname")       (2)
  .as(String.class)           (3)
  .all();                     (4)
1 查询 Person 集合。
2 选择 lastname 字段的不同值。字段名称根据域类型属性声明进行映射,并考虑潜在的 @Field 注释。
3 检索到的值将转换为所需的目標类型 - 在这种情况下为 String。如果存储的字段包含文档,也可以将值映射到更复杂的类型。
4 检索所有不同值作为 StringList。如果类型无法转换为所需的目標类型,此方法将抛出 DataAccessException

+= 地理空间查询

MongoDB 通过使用 $near$withingeoWithin$nearSphere 等运算符支持地理空间查询。Criteria 类上提供了特定于地理空间查询的方法。还有一些形状类(BoxCirclePoint)与地理空间相关的 Criteria 方法一起使用。

在 MongoDB 事务中使用 GeoSpatial 查询需要特别注意,请参阅 事务中的特殊行为

要了解如何执行 GeoSpatial 查询,请考虑以下 Venue 类(取自集成测试,并依赖于丰富的 MappingMongoConverter

Venue.java
@Document(collection="newyork")
public class Venue {

  @Id
  private String id;
  private String name;
  private double[] location;

  @PersistenceConstructor
  Venue(String name, double[] location) {
    super();
    this.name = name;
    this.location = location;
  }

  public Venue(String name, double x, double y) {
    super();
    this.name = name;
    this.location = new double[] { x, y };
  }

  public String getName() {
    return name;
  }

  public double[] getLocation() {
    return location;
  }

  @Override
  public String toString() {
    return "Venue [id=" + id + ", name=" + name + ", location="
        + Arrays.toString(location) + "]";
  }
}

要查找 Circle 内的位置,可以使用以下查询

Circle circle = new Circle(-73.99171, 40.738868, 0.01);
List<Venue> venues =
    template.find(new Query(Criteria.where("location").within(circle)), Venue.class);

要使用球面坐标在 Circle 内查找场所,可以使用以下查询

Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
List<Venue> venues =
    template.find(new Query(Criteria.where("location").withinSphere(circle)), Venue.class);

要查找 Box 内的场所,可以使用以下查询

//lower-left then upper-right
Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404));
List<Venue> venues =
    template.find(new Query(Criteria.where("location").within(box)), Venue.class);

要查找 Point 附近的场所,可以使用以下查询

Point point = new Point(-73.99171, 40.738868);
List<Venue> venues =
    template.find(new Query(Criteria.where("location").near(point).maxDistance(0.01)), Venue.class);
Point point = new Point(-73.99171, 40.738868);
List<Venue> venues =
    template.find(new Query(Criteria.where("location").near(point).minDistance(0.01).maxDistance(100)), Venue.class);

要使用球面坐标查找 Point 附近的场所,可以使用以下查询

Point point = new Point(-73.99171, 40.738868);
List<Venue> venues =
    template.find(new Query(
        Criteria.where("location").nearSphere(point).maxDistance(0.003712240453784)),
        Venue.class);

Geo-near 查询

在 2.2 中更改!
MongoDB 4.2 删除了对 geoNear 命令的支持,该命令以前用于运行 NearQuery

Spring Data MongoDB 2.2 MongoOperations#geoNear 使用 $geoNear 聚合 而不是 geoNear 命令来运行 NearQuery

以前在包装类型中返回的计算距离(使用 geoNear 命令时的 dis)现在嵌入到结果文档中。如果给定的域类型已经包含具有该名称的属性,则计算的距离将命名为 calculated-distance,并可能带有随机后缀。

目标类型可能包含一个以返回的距离命名的属性,以便(另外)将其直接读回域类型,如下所示。

GeoResults<VenueWithDistanceField> = template.query(Venue.class) (1)
    .as(VenueWithDistanceField.class)                            (2)
    .near(NearQuery.near(new GeoJsonPoint(-73.99, 40.73), KILOMETERS))
    .all();
1 用于标识目标集合和潜在查询映射的域类型。
2 包含类型为 Numberdis 字段的目标类型。

MongoDB 支持查询数据库以获取地理位置,并同时计算与给定原点的距离。使用 geo-near 查询,您可以表达诸如“查找周围 10 英里内的所有餐厅”之类的查询。为了让您这样做,MongoOperations 提供了 geoNear(…) 方法,这些方法接受 NearQuery 作为参数(以及已经熟悉的实体类型和集合),如以下示例所示

Point location = new Point(-73.99171, 40.738868);
NearQuery query = NearQuery.near(location).maxDistance(new Distance(10, Metrics.MILES));

GeoResults<Restaurant> = operations.geoNear(query, Restaurant.class);

我们使用 NearQuery 构建器 API 来设置一个查询,以返回围绕给定 Point 的所有 Restaurant 实例,距离为 10 英里。这里使用的 Metrics 枚举实际上实现了接口,以便其他指标也可以插入到距离中。Metric 由一个乘数支持,用于将给定指标的距离值转换为原生距离。这里显示的示例将 10 视为英里。使用内置指标之一(英里和公里)会自动触发在查询上设置球面标志。如果您想避免这种情况,请将纯 double 值传递到 maxDistance(…) 中。有关更多信息,请参阅 NearQueryDistanceJavaDoc

地理位置临近操作返回一个GeoResults包装对象,该对象封装了GeoResult实例。包装GeoResults允许访问所有结果的平均距离。单个GeoResult对象包含找到的实体及其到原点的距离。

GeoJSON 支持

MongoDB 支持 GeoJSON 和简单的(传统)坐标对用于地理空间数据。这些格式既可以用于存储,也可以用于查询数据。请参阅 MongoDB 手册关于 GeoJSON 支持 以了解要求和限制。

域类中的 GeoJSON 类型

在域类中使用 GeoJSON 类型非常简单。org.springframework.data.mongodb.core.geo 包含诸如GeoJsonPointGeoJsonPolygon 等类型。这些类型扩展了现有的org.springframework.data.geo 类型。以下示例使用GeoJsonPoint

public class Store {

	String id;

	/**
	 * { "type" : "Point", "coordinates" : [ x, y ] }
	 */
	GeoJsonPoint location;
}

如果 GeoJSON 对象的coordinates 表示纬度经度对,则经度纬度之前。
因此,GeoJsonPointgetX() 视为经度,将getY() 视为纬度

存储库查询方法中的 GeoJSON 类型

将 GeoJSON 类型用作存储库查询参数强制在创建查询时使用$geometry 运算符,如下面的示例所示

public interface StoreRepository extends CrudRepository<Store, String> {

	List<Store> findByLocationWithin(Polygon polygon);  (1)

}

/*
 * {
 *   "location": {
 *     "$geoWithin": {
 *       "$geometry": {
 *         "type": "Polygon",
 *         "coordinates": [
 *           [
 *             [-73.992514,40.758934],
 *             [-73.961138,40.760348],
 *             [-73.991658,40.730006],
 *             [-73.992514,40.758934]
 *           ]
 *         ]
 *       }
 *     }
 *   }
 * }
 */
repo.findByLocationWithin(                              (2)
  new GeoJsonPolygon(
    new Point(-73.992514, 40.758934),
    new Point(-73.961138, 40.760348),
    new Point(-73.991658, 40.730006),
    new Point(-73.992514, 40.758934)));                 (3)

/*
 * {
 *   "location" : {
 *     "$geoWithin" : {
 *        "$polygon" : [ [-73.992514,40.758934] , [-73.961138,40.760348] , [-73.991658,40.730006] ]
 *     }
 *   }
 * }
 */
repo.findByLocationWithin(                              (4)
  new Polygon(
    new Point(-73.992514, 40.758934),
    new Point(-73.961138, 40.760348),
    new Point(-73.991658, 40.730006)));
1 使用通用类型定义的存储库方法允许使用 GeoJSON 和传统格式调用它。
2 使用 GeoJSON 类型来使用$geometry 运算符。
3 请注意,GeoJSON 多边形需要定义一个闭合环。
4 使用传统格式$polygon 运算符。

指标和距离计算

然后 MongoDB $geoNear 运算符允许使用 GeoJSON 点或传统坐标对。

NearQuery.near(new Point(-73.99171, 40.738868))
{
  "$geoNear": {
    //...
    "near": [-73.99171, 40.738868]
  }
}
NearQuery.near(new GeoJsonPoint(-73.99171, 40.738868))
{
  "$geoNear": {
    //...
    "near": { "type": "Point", "coordinates": [-73.99171, 40.738868] }
  }
}

虽然语法不同,但无论集合中目标文档使用何种格式,服务器都可以接受两者。

距离计算存在很大差异。使用传统格式在类似地球的球体上进行弧度运算,而 GeoJSON 格式使用

为了避免严重的头痛,请确保将Metric 设置为所需的度量单位,这将确保正确计算距离。

换句话说

假设您有 5 个类似于以下的文档

{
    "_id" : ObjectId("5c10f3735d38908db52796a5"),
    "name" : "Penn Station",
    "location" : { "type" : "Point", "coordinates" : [  -73.99408, 40.75057 ] }
}
{
    "_id" : ObjectId("5c10f3735d38908db52796a6"),
    "name" : "10gen Office",
    "location" : { "type" : "Point", "coordinates" : [ -73.99171, 40.738868 ] }
}
{
    "_id" : ObjectId("5c10f3735d38908db52796a9"),
    "name" : "City Bakery ",
    "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
}
{
    "_id" : ObjectId("5c10f3735d38908db52796aa"),
    "name" : "Splash Bar",
    "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
}
{
    "_id" : ObjectId("5c10f3735d38908db52796ab"),
    "name" : "Momofuku Milk Bar",
    "location" : { "type" : "Point", "coordinates" : [ -73.985839, 40.731698 ] }
}

使用 GeoJSON 从[-73.99171, 40.738868] 获取 400 米半径内的所有文档将如下所示

示例 6. 使用 GeoJSON 的 GeoNear
{
    "$geoNear": {
        "maxDistance": 400, (1)
        "num": 10,
        "near": { type: "Point", coordinates: [-73.99171, 40.738868] },
        "spherical":true, (2)
        "key": "location",
        "distanceField": "distance"
    }
}

返回以下 3 个文档

{
    "_id" : ObjectId("5c10f3735d38908db52796a6"),
    "name" : "10gen Office",
    "location" : { "type" : "Point", "coordinates" : [ -73.99171, 40.738868 ] }
    "distance" : 0.0 (3)
}
{
    "_id" : ObjectId("5c10f3735d38908db52796a9"),
    "name" : "City Bakery ",
    "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
    "distance" : 69.3582262492474 (3)
}
{
    "_id" : ObjectId("5c10f3735d38908db52796aa"),
    "name" : "Splash Bar",
    "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
    "distance" : 69.3582262492474 (3)
}
1 中心点最大距离(以为单位)。
2 GeoJSON 始终在球体上进行操作。
3 中心点的距离(以为单位)。

现在,当使用传统坐标对时,如前所述,操作在弧度上进行。因此,我们在构建 `$geoNear` 命令时使用 `Metrics#KILOMETERS`。`Metric` 确保正确设置距离倍数。

示例 7. 使用传统坐标对的 GeoNear
{
    "$geoNear": {
        "maxDistance": 0.0000627142377, (1)
        "distanceMultiplier": 6378.137, (2)
        "num": 10,
        "near": [-73.99171, 40.738868],
        "spherical":true, (3)
        "key": "location",
        "distanceField": "distance"
    }
}

返回 3 个文档,就像 GeoJSON 变体一样

{
    "_id" : ObjectId("5c10f3735d38908db52796a6"),
    "name" : "10gen Office",
    "location" : { "type" : "Point", "coordinates" : [ -73.99171, 40.738868 ] }
    "distance" : 0.0 (4)
}
{
    "_id" : ObjectId("5c10f3735d38908db52796a9"),
    "name" : "City Bakery ",
    "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
    "distance" : 0.0693586286032982 (4)
}
{
    "_id" : ObjectId("5c10f3735d38908db52796aa"),
    "name" : "Splash Bar",
    "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
    "distance" : 0.0693586286032982 (4)
}
1 中心点最大距离(以弧度为单位)。
2 距离倍数,以便我们获得公里作为结果距离。
3 确保我们在 2d_sphere 索引上进行操作。
4 中心点距离(以公里为单位) - 乘以 1000 以匹配 GeoJSON 变体的

全文搜索

从 MongoDB 2.6 版本开始,您可以使用 `$text` 运算符运行全文查询。`TextQuery` 和 `TextCriteria` 中提供了特定于全文查询的方法和操作。在进行全文搜索时,请参阅 MongoDB 参考 以了解其行为和限制。

在您实际使用全文搜索之前,必须正确设置搜索索引。有关如何创建索引结构的更多详细信息,请参阅 文本索引。以下示例展示了如何设置全文搜索

db.foo.createIndex(
{
  title : "text",
  content : "text"
},
{
  weights : {
              title : 3
            }
}
)

可以定义并运行搜索 `coffee cake` 的查询,如下所示

示例 8. 全文查询
Query query = TextQuery
  .queryText(new TextCriteria().matchingAny("coffee", "cake"));

List<Document> page = template.find(query, Document.class);

要根据 `weights` 按相关性对结果进行排序,请使用 `TextQuery.sortByScore`。

示例 9. 全文查询 - 按得分排序
Query query = TextQuery
  .queryText(new TextCriteria().matchingAny("coffee", "cake"))
  .sortByScore() (1)
  .includeScore(); (2)

List<Document> page = template.find(query, Document.class);
1 使用 score 属性按相关性对结果进行排序,这会触发 `sort({'score': {'$meta': 'textScore'}})`。
2 使用 `TextQuery.includeScore()` 将计算出的相关性包含在结果 `Document` 中。

您可以通过在术语前添加 `-` 或使用 `notMatching` 来排除搜索术语,如以下示例所示(请注意,这两行具有相同的效果,因此是冗余的)

// search for 'coffee' and not 'cake'
TextQuery.queryText(new TextCriteria().matching("coffee").matching("-cake"));
TextQuery.queryText(new TextCriteria().matching("coffee").notMatching("cake"));

TextCriteria.matching 按原样获取提供的术语。因此,您可以通过将短语放在双引号之间(例如,`\"coffee cake\")` 或使用 `TextCriteria.phrase.` 来定义短语。以下示例展示了定义短语的两种方法

// search for phrase 'coffee cake'
TextQuery.queryText(new TextCriteria().matching("\"coffee cake\""));
TextQuery.queryText(new TextCriteria().phrase("coffee cake"));

您可以通过在TextCriteria上使用相应的方法来设置$caseSensitive$diacriticSensitive的标志。请注意,这两个可选标志是在 MongoDB 3.2 中引入的,除非显式设置,否则不会包含在查询中。

按示例查询

按示例查询 可用于模板 API 级别运行示例查询。

以下代码片段展示了如何按示例查询

类型化示例查询
Person probe = new Person();
probe.lastname = "stark";

Example example = Example.of(probe);

Query query = new Query(new Criteria().alike(example));
List<Person> result = template.find(query, Person.class);

默认情况下,Example 是严格类型化的。这意味着映射的查询包含类型匹配,将其限制为探测可分配类型。例如,当坚持使用默认类型键 (_class) 时,查询具有以下限制 (_class : { $in : [ com.acme.Person] })。

通过使用UntypedExampleMatcher,可以绕过默认行为并跳过类型限制。因此,只要字段名称匹配,几乎任何域类型都可以用作探测来创建引用,如下面的示例所示

示例 10. 非类型化示例查询
class JustAnArbitraryClassWithMatchingFieldName {
  @Field("lastname") String value;
}

JustAnArbitraryClassWithMatchingFieldNames probe = new JustAnArbitraryClassWithMatchingFieldNames();
probe.value = "stark";

Example example = Example.of(probe, UntypedExampleMatcher.matching());

Query query = new Query(new Criteria().alike(example));
List<Person> result = template.find(query, Person.class);

ExampleSpec中包含null值时,Spring Data Mongo 使用嵌入式文档匹配而不是点表示法属性匹配。这样做强制对所有属性值和嵌入式文档中的属性顺序进行精确的文档匹配。

如果您将不同的实体存储在单个集合中或选择不写入类型提示,那么UntypedExampleMatcher可能是您的正确选择。

此外,请记住,使用@TypeAlias需要MappingContext的急切初始化。为此,请配置initialEntitySet以确保对读取操作的正确别名解析。

Spring Data MongoDB 提供对不同匹配选项的支持

StringMatcher 选项
匹配 逻辑结果

DEFAULT(区分大小写)

{"firstname" : firstname}

DEFAULT(不区分大小写)

{"firstname" : { $regex: firstname, $options: 'i'}}

EXACT(区分大小写)

{"firstname" : { $regex: /^firstname$/}}

EXACT(不区分大小写)

{"firstname" : { $regex: /^firstname$/, $options: 'i'}}

STARTING(区分大小写)

{"firstname" : { $regex: /^firstname/}}

STARTING(不区分大小写)

{"firstname" : { $regex: /^firstname/, $options: 'i'}}

ENDING(区分大小写)

{"firstname" : { $regex: /firstname$/}}

ENDING(不区分大小写)

{"firstname" : { $regex: /firstname$/, $options: 'i'}}

CONTAINING(区分大小写)

{"firstname" : { $regex: /.*firstname.*/}}

CONTAINING(不区分大小写)

{"firstname" : { $regex: /.*firstname.*/, $options: 'i'}}

REGEX(区分大小写)

{"firstname" : { $regex: /firstname/}}

REGEX(不区分大小写)

{"firstname" : { $regex: /firstname/, $options: 'i'}}

查询与 JSON Schema 匹配的集合

您可以使用模式查询任何集合,以查找与 JSON 模式定义的结构匹配的文档,如下例所示

示例 11. 查询与 $jsonSchema 匹配的文档
MongoJsonSchema schema = MongoJsonSchema.builder().required("firstname", "lastname").build();

template.find(query(matchingDocumentStructure(schema)), Person.class);

请参考 JSON Schema 部分,了解有关 Spring Data MongoDB 中模式支持的更多信息。