Querying Documents

  • Querying Documents

  • Projection

  • Selecting fields

  • Additional Query Options

  • Hints

  • Cursor Batch Size

  • Collations

  • Read Preference

  • Comments

  • Query Distinct Values

  • GeoSpatial Queries

  • geoNear Queries

  • GeoJSON Support

  • Metrics and Distance calculation

  • Full-text Search

  • Query by Example :description: Spring Data MongoDB 提供了 Query 和 Criteria 类来创建查询。这些类提供了一致的、流畅的 API,支持嵌套谓词和 MongoDB 操作符。可以使用 Query 类来指定过滤条件、排序、字段选择以及其他查询选项。Criteria 类提供了一种链式、流畅的方式来构建复杂条件,包括相等、比较和布尔运算。

您可以使用 QueryCriteria 类来表达您的查询。它们的函数名称反映了本地 MongoDB 运算符名称,例如 ltlteis 等。QueryCriteria 类遵循流畅的 API 样式,以便您可以将多个方法条件和查询链接在一起,同时拥有易于理解的代码。为提高可读性,静态导入使您可以避免使用“new”关键字创建 QueryCriteria 实例。您还可以使用 BasicQuery 从纯 JSON 字符串创建 Query 实例,如下例所示:

You can use the Query and Criteria classes to express your queries. They have method names that mirror the native MongoDB operator names, such as lt, lte, is, and others. The Query and Criteria classes follow a fluent API style so that you can chain together multiple method criteria and queries while having easy-to-understand code. To improve readability, static imports let you avoid using the 'new' keyword for creating Query and Criteria instances. You can also use BasicQuery to create Query instances from plain JSON Strings, as shown in the following example: .Creating a Query instance from a plain JSON String

BasicQuery query = new BasicQuery("{ age : { $lt : 50 }, accounts.balance : { $gt : 1000.00 }}");
List<Person> result = mongoTemplate.find(query, Person.class);

Querying Documents in a Collection

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

Earlier, we saw how to retrieve a single document by using the findOne and findById methods on MongoTemplate. These methods return a single domain object right way or using a reactive API a Mono emitting a single element. We can also query for a collection of documents to be returned as a list of domain objects. Assuming that we have a number of Person objects with name and age stored as documents in a collection and that each person has an embedded account document with a balance, we can now run a query using the following code:

Querying for documents using the MongoTemplate
  • 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();

所有 find 函数都将 Query 对象作为参数。这个对象定义了用来执行查询的条件和选项。使用一个静态工厂函数名为 whereCriteria 对象来指定条件以实例化一个新的 Criteria 对象。我们建议对 org.springframework.data.mongodb.core.query.Criteria.whereQuery.query 使用静态导入以使查询更具可读性。

All find methods take a Query object as a parameter. This object defines the criteria and options used to perform the query. The criteria are specified by using a Criteria object that has a static factory method named where to instantiate a new Criteria object. We recommend using static imports for org.springframework.data.mongodb.core.query.Criteria.where and Query.query to make the query more readable.

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

The query should return a List or Flux of Person objects that meet the specified criteria. The rest of this section lists the methods of the Criteria and Query classes that correspond to the operators provided in MongoDB. Most methods return the Criteria object, to provide a fluent style for the API.

Example 1. Methods of the Criteria Class

Criteria 类提供以下方法,它们都对应 MongoDB 中的操作符:

The Criteria class provides the following methods, all of which correspond to operators in MongoDB:

  • Criteria all (Object o) Creates a criterion using the $all operator

  • Criteria and (String key) Adds a chained Criteria with the specified key to the current Criteria and returns the newly created one

  • Criteria andOperator (Criteria…​ criteria) Creates an and query using the $and operator for all of the provided criteria (requires MongoDB 2.0 or later)

  • Criteria andOperator (Collection<Criteria> criteria) Creates an and query using the $and operator for all of the provided criteria (requires MongoDB 2.0 or later)

  • Criteria elemMatch (Criteria c) Creates a criterion using the $elemMatch operator

  • Criteria exists (boolean b) Creates a criterion using the $exists operator

  • Criteria gt (Object o) Creates a criterion using the $gt operator

  • Criteria gte (Object o) Creates a criterion using the $gte operator

  • Criteria in (Object…​ o) Creates a criterion using the $in operator for a varargs argument.

  • Criteria in (Collection<?> collection) Creates a criterion using the $in operator using a collection

  • Criteria is (Object o) Creates a criterion using field matching ({ key:value }). If the specified value is a document, the order of the fields and exact equality in the document matters.

  • Criteria lt (Object o) Creates a criterion using the $lt operator

  • Criteria lte (Object o) Creates a criterion using the $lte operator

  • Criteria mod (Number value, Number remainder) Creates a criterion using the $mod operator

  • Criteria ne (Object o) Creates a criterion using the $ne operator

  • Criteria nin (Object…​ o) Creates a criterion using the $nin operator

  • Criteria norOperator (Criteria…​ criteria) Creates an nor query using the $nor operator for all of the provided criteria

  • Criteria norOperator (Collection<Criteria> criteria) Creates an nor query using the $nor operator for all of the provided criteria

  • Criteria not () Creates a criterion using the $not meta operator which affects the clause directly following

  • Criteria orOperator (Criteria…​ criteria) Creates an or query using the $or operator for all of the provided criteria

  • Criteria orOperator (Collection<Criteria> criteria) Creates an or query using the $or operator for all of the provided criteria

  • Criteria regex (String re) Creates a criterion using a $regex

  • Criteria sampleRate (double sampleRate) Creates a criterion using the $sampleRate operator

  • Criteria size (int s) Creates a criterion using the $size operator

  • Criteria type (int t) Creates a criterion using the $type operator

  • Criteria matchingDocumentStructure (MongoJsonSchema schema) Creates a criterion using the $jsonSchema operator for JSON schema criteria. $jsonSchema can only be applied on the top level of a query and not property specific. Use the properties attribute of the schema to match against nested fields.

  • Criteria bits() is the gateway to MongoDB bitwise query operators like $bitsAllClear.

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

The Criteria class also provides the following methods for geospatial queries.

  • Criteria within (Circle circle) Creates a geospatial criterion using $geoWithin $center operators.

  • Criteria within (Box box) Creates a geospatial criterion using a $geoWithin $box operation.

  • Criteria withinSphere (Circle circle) Creates a geospatial criterion using $geoWithin $center operators.

  • Criteria near (Point point) Creates a geospatial criterion using a $near operation

  • Criteria nearSphere (Point point) Creates a geospatial criterion using $nearSphere$center operations. This is only available for MongoDB 1.7 and higher.

  • Criteria minDistance (double minDistance) Creates a geospatial criterion using the $minDistance operation, for use with $near.

  • Criteria maxDistance (double maxDistance) Creates a geospatial criterion using the $maxDistance operation, for use with $near.

Query 类有一些其他方法,允许选择某些字段以及限制和排序结果。

The Query class has some additional methods that allow to select certain fields as well as to limit and sort the result.

Example 2. Methods of the Query class
  • Query addCriteria (Criteria criteria) used to add additional criteria to the query

  • Field fields () used to define fields to be included in the query results

  • Query limit (int limit) used to limit the size of the returned results to the provided limit (used for paging)

  • Query skip (int skip) used to skip the provided number of documents in the results (used for paging)

  • Query with (Sort sort) used to provide sort definition for the results

  • Query with (ScrollPosition position) used to provide a scroll position (Offset- or Keyset-based pagination) to start or resume a Scroll

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

The template API allows direct usage of result projections that enable you to map queries against a given domain type while projecting the operation result onto another one as outlined below.

class

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

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

For more information on result projections please refer to the Projections section of the documentation.

Selecting fields

MongoDB 支持查询返回的 projecting fields。基于字段名称,投影可以包括和排除字段(除非明确排除,否则始终包括 _id 字段)。

MongoDB supports projecting fields returned by a query. A projection can include and exclude fields (the _id field is always included unless explicitly excluded) based on their name.

Example 3. Selecting result fields
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 Result will contain both _id and last_name via { "last_name" : 1 }.
2 Result will only contain the last_name via { "_id" : 0, "last_name" : 1 }.
3 Result will contain the _id and entire address object via { "address" : 1 }.
4 Result will contain the _id and and address object that only contains the city field via { "address.city" : 1 }.

从 MongoDB 4.4 开始,你可以对字段投影使用聚合表达式,如下所示:

Starting with MongoDB 4.4 you can use aggregation expressions for field projections as shown below:

Example 4. Computing result fields using expressions
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 Use a native expression. The used field name must refer to field names within the database document.
2 Assign the field name to which the expression result is projected. The resulting field name is not mapped against the domain model.
3 Use an AggregationExpression. Other than native MongoExpression, field names are mapped to the ones used in the domain model.
4 Use SpEL along with an AggregationExpression to invoke expression functions. Field names are mapped to the ones used in the domain model.

`@Query(fields="…")`允许在 `Repository`级别使用表达式字段投影,如 MongoDB JSON-based Query Methods and Field Restriction中所述。

@Query(fields="…") allows usage of expression field projections at Repository level as described in MongoDB JSON-based Query Methods and Field Restriction.

Additional Query Options

MongoDB 提供了多种方法向查询应用元信息,例如注释或批大小。直接使用 Query API 时,有几种方法可以实现这些选项。

MongoDB offers various ways of applying meta information, like a comment or a batch size, to a query.Using the Query API directly there are several methods for those options.

Hints

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

Index hints can be applied in two ways, using the index name or its field definition.

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

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

Cursor Batch Size

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

The cursor batch size defines the number of documents to return in each response batch.

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

Collations

对集合操作使用排序涉及在查询或操作选项中指定 Collation 实例,如下例所示:

Using collations with collection operations is a matter of specifying a Collation instance in your query or operation options, as the following two examples show:

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

Read Preference

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

The ReadPreference to use can be set directly on the Query object to be run as outlined below.

template.find(Person.class)
    .matching(query(where(...)).withReadPreference(ReadPreference.secondary()))
    .all();

Query 实例上设置的首选将取代 ReadPreference MongoTemplate 的默认值。

The preference set on the Query instance will supersede the default ReadPreference of MongoTemplate.

Comments

查询可以配备注释,这使得在服务器日志中查找查询变得更加容易。

Queries can be equipped with comments which makes them easier to look up in server logs.

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

Query Distinct Values

MongoDB 提供了一个操作,通过使用查询从结果文档中获取单个字段的不同值。结果值不必具有相同的数据类型,该特性也不限于简单类型。出于转换和类型的考虑,实际结果类型在检索中很重要。以下示例展示了如何查询不同值:

MongoDB provides an operation to obtain distinct values for a single field by using a query from the resulting documents. Resulting values are not required to have the same data type, nor is the feature limited to simple types. For retrieval, the actual result type does matter for the sake of conversion and typing. The following example shows how to query for distinct values:

Example 5. Retrieving distinct values
template.query(Person.class)  1
  .distinct("lastname")       2
  .all();                     3
1 Query the Person collection.
2 Select distinct values of the lastname field. The field name is mapped according to the domain types property declaration, taking potential @Field annotations into account.
3 Retrieve all distinct values as a List of Object (due to no explicit result type being specified).

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

Retrieving distinct values into a Collection of Object is the most flexible way, as it tries to determine the property value of the domain type and convert results to the desired type or mapping Document structures.

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

Sometimes, when all values of the desired field are fixed to a certain type, it is more convenient to directly obtain a correctly typed Collection, as shown in the following example:

Example 6. Retrieving strongly typed distinct values
template.query(Person.class)  1
  .distinct("lastname")       2
  .as(String.class)           3
  .all();                     4
1 Query the collection of Person.
2 Select distinct values of the lastname field. The fieldname is mapped according to the domain types property declaration, taking potential @Field annotations into account.
3 Retrieved values are converted into the desired target type — in this case, String. It is also possible to map the values to a more complex type if the stored field contains a document.
4 Retrieve all distinct values as a List of String. If the type cannot be converted into the desired target type, this method throws a DataAccessException.

+= 地理空间查询

+= GeoSpatial Queries

MongoDB 通过使用`$near`、$withingeoWithin$nearSphere 等运算符支持地理空间查询。Criteria 类中有专门针对地理空间查询的方法。还有几个形状类(BoxCirclePoint),它们与地理空间相关的 Criteria 方法结合使用。

MongoDB supports GeoSpatial queries through the use of operators such as $near, $within, geoWithin, and $nearSphere. Methods specific to geospatial queries are available on the Criteria class. There are also a few shape classes (Box, Circle, and Point) that are used in conjunction with geospatial related Criteria methods.

在 MongoDB 事务中使用 GeoSpatial 查询时需要小心,请参阅Special behavior inside transactions

Using GeoSpatial queries requires attention when used within MongoDB transactions, see Special behavior inside transactions.

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

To understand how to perform GeoSpatial queries, consider the following Venue class (taken from the integration tests and relying on the rich MappingMongoConverter):

Example 7. 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 内的位置,可以使用以下查询:

To find locations within a Circle, you can use the following query:

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 内查找场所,可以使用以下查询:

To find venues within a Circle using spherical coordinates, you can use the following query:

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 内的场所,可以使用以下查询:

To find venues within a Box, you can use the following query:

//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 附近的场所,可以使用以下查询:

To find venues near a Point, you can use the following queries:

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 附近的场所,可以使用以下查询:

To find venues near a Point using spherical coordinates, you can use the following query:

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 Queries

Changed in 2.2! MongoDB 4.2 移除了对 geoNear 命令的支持,该命令之前用于运行 NearQuery

Changed in 2.2! MongoDB 4.2 removed support for the geoNear command which had been previously used to run the NearQuery.

Spring Data MongoDB 2.2 MongoOperations#geoNear 使用 $geoNear aggregation 而非 geoNear 命令来运行 NearQuery

Spring Data MongoDB 2.2 MongoOperations#geoNear uses the $geoNear aggregation instead of the geoNear command to run a NearQuery.

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

The calculated distance (the dis when using a geoNear command) previously returned within a wrapper type now is embedded into the resulting document. If the given domain type already contains a property with that name, the calculated distance is named calculated-distance with a potentially random postfix.

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

Target types may contain a property named after the returned distance to (additionally) read it back directly into the domain type as shown below.

GeoResults<VenueWithDistanceField> = template.query(Venue.class) 1
    .as(VenueWithDistanceField.class)                            2
    .near(NearQuery.near(new GeoJsonPoint(-73.99, 40.73), KILOMETERS))
    .all();
1 Domain type used to identify the target collection and potential query mapping.
2 Target type containing a dis field of type Number.

MongoDB 支持同时查询数据库中的地理位置并计算到给定原点距离的功能。通过 geon-near 查询,你可以表达诸如“查找周围 10 英里内的所有餐馆”之类的查询。为了让你做到这一点,MongoOperations 提供了 geoNear(…​) 方法,该方法以 NearQuery 作为参数(以及已经熟悉的实体类型和集合),如下例所示:

MongoDB supports querying the database for geo locations and calculating the distance from a given origin at the same time. With geo-near queries, you can express queries such as "find all restaurants in the surrounding 10 miles". To let you do so, MongoOperations provides geoNear(…) methods that take a NearQuery as an argument (as well as the already familiar entity type and collection), as shown in the following example:

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(…)。有关更多信息,请参阅 JavaDoc 中的 NearQueryDistance

We use the NearQuery builder API to set up a query to return all Restaurant instances surrounding the given Point out to 10 miles. The Metrics enum used here actually implements an interface so that other metrics could be plugged into a distance as well. A Metric is backed by a multiplier to transform the distance value of the given metric into native distances. The sample shown here would consider the 10 to be miles. Using one of the built-in metrics (miles and kilometers) automatically triggers the spherical flag to be set on the query. If you want to avoid that, pass plain double values into maxDistance(…). For more information, see the JavaDoc of NearQuery and Distance.

geo-near 操作返回一个封装 GeoResult 实例的 GeoResults 包装对象。包装 GeoResults 允许访问所有结果的平均距离。一个 GeoResult 对象承载找到的实体及其到原点的距离。

The geo-near operations return a GeoResults wrapper object that encapsulates GeoResult instances. Wrapping GeoResults allows accessing the average distance of all results. A single GeoResult object carries the entity found plus its distance from the origin.

GeoJSON Support

MongoDB 为地理空间数据支持 GeoJSON 和简单的(旧版)坐标对。这些格式都可用于存储和查询数据。请参阅 MongoDB manual on GeoJSON support 以了解要求和限制。

MongoDB supports GeoJSON and simple (legacy) coordinate pairs for geospatial data. Those formats can both be used for storing as well as querying data. See the MongoDB manual on GeoJSON support to learn about requirements and restrictions.

GeoJSON Types in Domain Classes

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

Usage of GeoJSON types in domain classes is straightforward. The org.springframework.data.mongodb.core.geo package contains types such as GeoJsonPoint, GeoJsonPolygon, and others. These types are extend the existing org.springframework.data.geo types. The following example uses a GeoJsonPoint:

public class Store {

	String id;

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

如果 GeoJSON 对象的 坐标 表示_纬度_和_经度_对,则_经度_在前,然后是_纬度_。因此,GeoJsonPointgetX() 视为_经度_,将 getY() 视为_纬度_。

If the coordinates of a GeoJSON object represent latitude and longitude pairs, the longitude goes first followed by latitude. GeoJsonPoint therefore treats getX() as longitude and getY() as latitude.

GeoJSON Types in Repository Query Methods

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

Using GeoJSON types as repository query parameters forces usage of the $geometry operator when creating the query, as the following example shows:

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 Repository method definition using the commons type allows calling it with both the GeoJSON and the legacy format.
2 Use GeoJSON type to make use of $geometry operator.
3 Note that GeoJSON polygons need to define a closed ring.
4 Use the legacy format $polygon operator.

Metrics and Distance calculation

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

Then MongoDB $geoNear operator allows usage of a GeoJSON Point or legacy coordinate pairs.

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] }
  }
}

尽管语法不同,但无论集合中目标 Document 使用什么格式,服务器都可以接受这两种格式。

Though syntactically different the server is fine accepting both no matter what format the target Document within the collection is using.

距离计算存在巨大差异。使用旧格式在类球体的_地球_上进行操作,而 GeoJSON 格式使用 Meters

There is a huge difference in the distance calculation. Using the legacy format operates upon Radians on an Earth like sphere, whereas the GeoJSON format uses Meters.

为避免严重的头疼,确保将“Metric”设置为所需的测量单位,这可确保正确计算距离。

To avoid a serious headache make sure to set the Metric to the desired unit of measure which ensures the distance to be calculated correctly.

换句话说:

In other words:

假设您有 5 个类似于以下的 Document:

Assume you’ve got 5 Documents like the ones below:

{
    "_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 米半径内的所有文档看起来如下所示:

Fetching all Documents within a 400 Meter radius from [-73.99171, 40.738868] would look like this using GeoJSON:

Example 8. GeoNear with GeoJSON
{
    "$geoNear": {
        "maxDistance": 400, 1
        "num": 10,
        "near": { type: "Point", coordinates: [-73.99171, 40.738868] },
        "spherical":true, 2
        "key": "location",
        "distanceField": "distance"
    }
}

返回以下 3 个 Document:

Returning the following 3 Documents:

{
    "_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 Maximum distance from center point in Meters.
2 GeoJSON always operates upon a sphere.
3 Distance from center point in Meters.

现在,当使用旧的坐标对时,正如之前讨论过的,操作在 Radians 上进行。因此,在构造 $geoNear 命令时,我们使用了 Metrics#KILOMETERSMetric 确保正确设置距离倍率。

Now, when using legacy coordinate pairs one operates upon Radians as discussed before. So we use Metrics#KILOMETERS when constructing the `$geoNear command. The Metric makes sure the distance multiplier is set correctly.

Example 9. GeoNear with Legacy Coordinate Pairs
{
    "$geoNear": {
        "maxDistance": 0.0000627142377, 1
        "distanceMultiplier": 6378.137, 2
        "num": 10,
        "near": [-73.99171, 40.738868],
        "spherical":true, 3
        "key": "location",
        "distanceField": "distance"
    }
}

返回 3 个 Document,与 GeoJSON 变体相同:

Returning the 3 Documents just like the GeoJSON variant:

{
    "_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 Maximum distance from center point in Radians.
2 The distance multiplier so we get Kilometers as resulting distance.
3 Make sure we operate on a 2d_sphere index.
4 Distance from center point in Kilometers - take it times 1000 to match Meters of the GeoJSON variant.

Full-text Search

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

Since version 2.6 of MongoDB, you can run full-text queries by using the $text operator. Methods and operations specific to full-text queries are available in TextQuery and TextCriteria. When doing full text search, see the MongoDB reference for its behavior and limitations.

在実際に使用全文搜索之前,必须正确设置搜索索引。有关如何创建索引结构的更多详细信息,请参见 Text Index。以下示例展示了如何设置全文搜索:

Before you can actually use full-text search, you must set up the search index correctly. See Text Index for more detail on how to create index structures. The following example shows how to set up a full-text search:

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

可以将搜索 coffee cake 的查询定义并运行如下:

A query searching for coffee cake can be defined and run as follows:

Example 10. Full Text Query
Query query = TextQuery
  .queryText(new TextCriteria().matchingAny("coffee", "cake"));

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

要按照 weights 的相关性对结果进行排序,请使用 TextQuery.sortByScore

To sort results by relevance according to the weights use TextQuery.sortByScore.

Example 11. Full Text Query - Sort by Score
Query query = TextQuery
  .queryText(new TextCriteria().matchingAny("coffee", "cake"))
  .sortByScore() 1
  .includeScore(); 2

List<Document> page = template.find(query, Document.class);
1 Use the score property for sorting results by relevance which triggers .sort({'score': {'$meta': 'textScore'}}).
2 Use TextQuery.includeScore() to include the calculated relevance in the resulting Document.

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

You can exclude search terms by prefixing the term with - or by using notMatching, as shown in the following example (note that the two lines have the same effect and are thus redundant):

// 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. 来定义短语。以下示例显示了定义短语的两种方法:

TextCriteria.matching takes the provided term as is. Therefore, you can define phrases by putting them between double quotation marks (for example, \"coffee cake\") or using by TextCriteria.phrase. The following example shows both ways of defining a 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 中引入,并且必须明确设置才能包含在查询中。

You can set flags for $caseSensitive and $diacriticSensitive by using the corresponding methods on TextCriteria. Note that these two optional flags have been introduced in MongoDB 3.2 and are not included in the query unless explicitly set.

Query by Example

Query by Example可以在模板 API 级别运行示例查询上使用。

Query by Example can be used on the Template API level run example queries.

以下代码段显示了如何按示例进行查询:

The following snipped shows how to query by example:

Typed Example Query
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] })。

By default Example is strictly typed. This means that the mapped query has an included type match, restricting it to probe assignable types. For example, when sticking with the default type key (_class), the query has restrictions such as (_class : { $in : [ com.acme.Person] }).

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

By using the UntypedExampleMatcher, it is possible to bypass the default behavior and skip the type restriction. So, as long as field names match, nearly any domain type can be used as the probe for creating the reference, as the following example shows:

Example 12. Untyped Example Query
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 使用嵌入式文档匹配而不是点表示法属性匹配。这样做会强制对所有属性值和嵌入式文档中的属性顺序进行完全文档匹配。

When including null values in the ExampleSpec, Spring Data Mongo uses embedded document matching instead of dot notation property matching. Doing so forces exact document matching for all property values and the property order in the embedded document.

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

UntypedExampleMatcher is likely the right choice for you if you are storing different entities within a single collection or opted out of writing type hints.

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

Also, keep in mind that using @TypeAlias requires eager initialization of the MappingContext. To do so, configure initialEntitySet to to ensure proper alias resolution for read operations.

Spring Data MongoDB 为不同的匹配选项提供了支持:

Spring Data MongoDB provides support for different matching options:

Example 13. StringMatcher options
Matching Logical result

DEFAULT (case-sensitive)

{"firstname" : firstname}

DEFAULT (case-insensitive)

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

EXACT (case-sensitive)

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

EXACT (case-insensitive)

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

STARTING (case-sensitive)

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

STARTING (case-insensitive)

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

ENDING (case-sensitive)

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

ENDING (case-insensitive)

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

CONTAINING (case-sensitive)

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

CONTAINING (case-insensitive)

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

REGEX (case-sensitive)

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

REGEX (case-insensitive)

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

Query a collection for matching JSON Schema

你可以使用模式查询文档集合,以便找到与 JSON 模式定义的给定结构匹配的文档,如下例所示:

You can use a schema to query any collection for documents that match a given structure defined by a JSON schema, as the following example shows:

Example 14. Query for Documents matching a $jsonSchema
MongoJsonSchema schema = MongoJsonSchema.builder().required("firstname", "lastname").build();

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

请参阅 JSON Schema 部分以了解有关 Spring Data MongoDB 中架构支持的更多信息。

Please refer to the JSON Schema section to learn more about the schema support in Spring Data MongoDB.