查询文档
你可以使用 Query 和 Criteria 类来表达你的查询。它们的方法名称与原生 MongoDB 操作符名称相对应,例如 lt、lte、is 等。Query 和 Criteria 类遵循流畅的 API 风格,因此你可以将多个方法条件和查询链式调用,同时保持代码易于理解。为了提高可读性,静态导入可以让你避免使用 new 关键字来创建 Query 和 Criteria 实例。你还可以使用 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 上使用 findOne 和 findById 方法来检索单个文档。这些方法直接返回一个单一的领域对象,或者使用响应式 API 返回一个发出单个元素的 Mono。我们也可以查询一组文档,并将其作为领域对象的列表返回。假设我们有许多 Person 对象,其姓名和年龄作为文档存储在集合中,并且每个人都有一个包含余额的嵌入式账户文档,那么我们可以使用以下代码运行查询:
- Imperative
- Reactive
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.where 和 Query.query,以使查询更具可读性。
查询应返回满足指定条件的 Person 对象的 List 或 Flux。本节其余部分列出了与 MongoDB 提供的运算符相对应的 Criteria 和 Query 类的方法。大多数方法返回 Criteria 对象,以提供流畅的 API 风格。
Criteria 类的方法
Criteria 类提供了以下方法,所有这些方法都对应 MongoDB 中的操作符:
- 
Criteriaall(Object o)使用$all操作符创建一个查询条件
- 
Criteriaand(String key)向当前Criteria添加一个带有指定key的链式Criteria,并返回新创建的Criteria
- 
CriteriaandOperator(Criteria… criteria)使用$and操作符为所有提供的条件创建一个与查询(需要 MongoDB 2.0 或更高版本)
- 
CriteriaandOperator(Collection<Criteria> criteria)使用$and操作符为所有提供的条件创建一个与查询(需要 MongoDB 2.0 或更高版本)
- 
CriteriaelemMatch(Criteria c)使用$elemMatch操作符创建一个查询条件
- 
Criteriaexists(boolean b)使用$exists操作符创建一个查询条件
- 
Criteriagt(Object o)使用$gt操作符创建一个查询条件
- 
Criteriagte(Object o)使用$gte操作符创建一个查询条件
- 
Criteriain(Object… o)使用$in操作符为可变参数创建一个查询条件
- 
Criteriain(Collection<?> collection)使用$in操作符为一个集合创建一个查询条件
- 
Criteriais(Object o)使用字段匹配 ({ key:value }) 创建一个查询条件。如果指定的值是一个文档,则文档中字段的顺序和精确相等性将影响匹配结果。
- 
Criterialt(Object o)使用$lt操作符创建一个查询条件
- 
Criterialte(Object o)使用$lte操作符创建一个查询条件
- 
Criteriamod(Number value, Number remainder)使用$mod操作符创建一个查询条件
- 
Criteriane(Object o)使用$ne操作符创建一个查询条件
- 
Criterianin(Object… o)使用$nin操作符创建一个查询条件
- 
CriterianorOperator(Criteria… criteria)使用$nor操作符为所有提供的条件创建一个或非查询
- 
CriterianorOperator(Collection<Criteria> criteria)使用$nor操作符为所有提供的条件创建一个或非查询
- 
Criterianot()使用$not元操作符创建一个查询条件,该操作符直接影响紧随其后的子句
- 
CriteriaorOperator(Criteria… criteria)使用$or操作符为所有提供的条件创建一个或查询
- 
CriteriaorOperator(Collection<Criteria> criteria)使用$or操作符为所有提供的条件创建一个或查询
- 
Criteriaregex(String re)使用$regex创建一个查询条件
- 
CriteriasampleRate(double sampleRate)使用$sampleRate操作符创建一个查询条件
- 
Criteriasize(int s)使用$size操作符创建一个查询条件
- 
Criteriatype(int t)使用$type操作符创建一个查询条件
- 
CriteriamatchingDocumentStructure(MongoJsonSchema schema)使用$jsonSchema操作符为 JSON schema criteria 创建一个查询条件。$jsonSchema只能应用于查询的顶层,而不能应用于特定属性。使用 schema 的properties属性来匹配嵌套字段。
- 
Criteriabits() 是 MongoDB 位查询操作符(如$bitsAllClear)的入口。
Criteria 类还提供了以下用于地理空间查询的方法。
- 
Criteriawithin(Circle circle)使用$geoWithin $center运算符创建地理空间条件。
- 
Criteriawithin(Box box)使用$geoWithin $box操作创建地理空间条件。
- 
CriteriawithinSphere(Circle circle)使用$geoWithin $center运算符创建地理空间条件。
- 
Criterianear(Point point)使用$near操作创建地理空间条件。
- 
CriterianearSphere(Point point)使用$nearSphere$center操作创建地理空间条件。此功能仅适用于 MongoDB 1.7 及更高版本。
- 
CriteriaminDistance(double minDistance)使用$minDistance操作创建地理空间条件,与 $near 一起使用。
- 
CriteriamaxDistance(double maxDistance)使用$maxDistance操作创建地理空间条件,与 $near 一起使用。
Query 类提供了一些额外的方法,允许选择特定字段以及限制和排序结果。
Query 类的方法
- 
QueryaddCriteria(Criteria criteria)用于向查询中添加额外的条件
- 
Fieldfields()用于定义查询结果中包含的字段
- 
Querylimit(int limit)用于将返回结果的大小限制为提供的限制值(用于分页)
- 
Queryskip(int skip)用于跳过结果中指定数量的文档(用于分页)
- 
Querywith(Sort sort)用于为结果提供排序定义
- 
Querywith(ScrollPosition position)用于提供一个滚动位置(基于偏移量或键集的分页)以开始或恢复Scroll
模板 API 允许直接使用结果投影,使您能够针对给定域类型映射查询,同时将操作结果投影到另一个类型上,如下所述。
class
template.query(SWCharacter.class)
    .as(Jedi.class)
有关结果投影的更多信息,请参阅文档的投影部分。
选择字段
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
- 结果将包含 - _id和- last_name,通过- { "last_name" : 1 }指定。
- 结果将仅包含 - last_name,通过- { "_id" : 0, "last_name" : 1 }指定。
- 结果将包含 - _id和整个- address对象,通过- { "address" : 1 }指定。
- 结果将包含 - _id和仅包含- city字段的- address对象,通过- { "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");
- 使用原生表达式。所使用的字段名必须引用数据库文档中的字段名。 
- 将表达式结果投射到的字段名进行赋值。生成的字段名不会映射到领域模型中。 
- 使用 - AggregationExpression。与原生- MongoExpression不同,字段名会映射到领域模型中使用的字段名。
- 结合 - AggregationExpression使用 SpEL 来调用表达式函数。字段名会映射到领域模型中使用的字段名。
@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 = Collation.of("de");
Query query = new Query(Criteria.where("firstName").is("Amél"))
    .collation(collation);
List<Person> results = template.find(query, Person.class);
读取偏好
可以在 Query 对象上直接设置要使用的 ReadPreference,如下所示。
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
- 查询 - Person集合。
- 选择 - lastname字段的不同值。字段名称根据域类型属性声明进行映射,并考虑潜在的- @Field注解。
- 检索所有不同的值作为 - Object的- List(由于未指定明确的结果类型)。
将唯一值检索到 Object 的 Collection 中是最灵活的方式,因为它尝试确定域类型的属性值,并将结果转换为所需的类型或映射 Document 结构。
有时,当所需字段的所有值都被固定为某种类型时,直接获取一个正确类型的 Collection 会更加方便,如下例所示:
示例 5. 检索强类型的不同值
template.query(Person.class)  1
  .distinct("lastname")       2
  .as(String.class)           3
  .all();                     4
- 查询 - Person集合。
- 选择 - lastname字段的唯一值。字段名称根据域类型属性声明进行映射,同时考虑潜在的- @Field注解。
- 检索到的值将转换为所需的目标类型 — 在本例中为 - String。如果存储的字段包含文档,还可以将值映射为更复杂的类型。
- 将所有唯一值作为 - String的- List检索。如果类型无法转换为所需的目标类型,此方法将抛出- DataAccessException。
地理空间查询
MongoDB 支持通过使用如 $near、$within、geoWithin 和 $nearSphere 等操作符进行地理空间查询。在 Criteria 类中提供了专门用于地理空间查询的方法。此外,还有一些形状类(Box、Circle 和 Point)与地理空间相关的 Criteria 方法结合使用。
在使用 MongoDB 事务时,使用地理空间查询需要特别注意,请参阅 事务内的特殊行为。
要理解如何进行地理空间查询,可以参考以下 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);
地理邻近查询
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();
- 用于标识目标集合和潜在查询映射的域类型。 
- 包含 - dis字段的目标类型,字段类型为- Number。
MongoDB 支持在查询数据库时获取地理位置信息,并同时计算与给定原点的距离。通过地理邻近查询(geo-near queries),你可以表达诸如“查找周围 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 周围 10 英里范围内的所有 Restaurant 实例。这里使用的 Metrics 枚举实际上实现了一个接口,因此其他度量单位也可以插入到距离计算中。Metric 由一个乘数支持,用于将给定度量单位的距离值转换为原生距离。此处显示的示例将 10 视为英里。使用内置的度量单位之一(英里和千米)会自动触发在查询中设置球形标志。如果你想避免这种情况,可以将普通的 double 值传递给 maxDistance(…)。有关更多信息,请参阅 NearQuery 和 Distance 的 Javadoc。
地理邻近操作返回一个 GeoResults 包装对象,该对象封装了 GeoResult 实例。通过包装 GeoResults,可以访问所有结果的平均距离。单个 GeoResult 对象包含找到的实体及其与起点的距离。
GeoJSON 支持
MongoDB 支持使用 GeoJSON 和简单的(遗留的)坐标对来存储地理空间数据。这两种格式都可以用于数据的存储和查询。有关要求和限制的详细信息,请参阅 MongoDB 关于 GeoJSON 支持的手册。
域类中的 GeoJSON 类型
在领域类中使用 GeoJSON 类型非常简单。org.springframework.data.mongodb.core.geo 包中包含诸如 GeoJsonPoint、GeoJsonPolygon 等类型。这些类型扩展了现有的 org.springframework.data.geo 类型。以下示例使用了 GeoJsonPoint:
public class Store {
	String id;
	/**
	 * { "type" : "Point", "coordinates" : [ x, y ] }
	 */
	GeoJsonPoint location;
}
如果 GeoJSON 对象的 coordinates 表示的是纬度和经度对,那么经度在前,纬度在后。
因此,GeoJsonPoint 将 getX() 视为经度,将 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)));
- 使用 commons 类型定义的仓库方法允许使用 GeoJSON 和传统格式调用它。 
- 使用 GeoJSON 类型以利用 - $geometry操作符。
- 请注意,GeoJSON 多边形需要定义一个闭合环。 
- 使用传统格式的 - $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
}
- 距中心点的最大距离,单位为米。 
- GeoJSON 始终基于球面进行计算。 
- 距中心点的距离,单位为米。 
现在,当使用传统的坐标对时,我们操作的是之前讨论过的弧度。因此,在构造 $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"
    }
}
返回与 GeoJSON 变体相同的 3 个文档:
{
    "_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
}
- 从中心点出发的最大距离,单位为弧度。 
- 距离乘数,以便我们得到以公里为单位的最终距离。 
- 确保我们在 2d_sphere 索引上操作。 
- 从中心点出发的距离,单位为公里——将其乘以 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);
- 使用 - score属性按相关性对结果进行排序,这会触发- .sort({'score': {'$meta': 'textScore'}})。
- 使用 - 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 中引入,除非显式设置,否则不会包含在查询中。
示例查询
按示例查询 可以在 Template 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 的集合
你可以使用模式(schema)来查询任何集合中匹配由 JSON 模式定义的特定结构的文档,如下例所示:
示例 11:查询匹配 $jsonSchema 的文档
MongoJsonSchema schema = MongoJsonSchema.builder().required("firstname", "lastname").build();
template.find(query(matchingDocumentStructure(schema)), Person.class);
请参阅 JSON Schema 部分以了解 Spring Data MongoDB 中的模式支持。