|
此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Data MongoDB 4.5.2! |
查询文档
您可以使用Query和Criteria类来表达您的查询。
它们具有镜像本机 MongoDB 运算符名称的方法名称,例如lt,lte,is,等。
这Query和Criteria类遵循流畅的 API 样式,因此您可以将多个方法条件和查询链接在一起,同时使用易于理解的代码。
为了提高可读性,静态导入可让您避免使用“new”关键字创建Query和Criteria实例。
您还可以使用BasicQuery创建Query实例,如以下示例所示:
BasicQuery query = new BasicQuery("{ age : { $lt : 50 }, accounts.balance : { $gt : 1000.00 }}");
List<Person> result = mongoTemplate.find(query, Person.class);
查询集合中的文档
之前,我们看到了如何使用findOne和findById方法MongoTemplate.
这些方法以正确的方式返回单个域对象,或者使用响应式 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();
所有查找方法都采用Queryobject 作为参数。
此对象定义用于执行查询的条件和选项。
这些条件是通过使用Criteria具有名为where实例化新的Criteria对象。
我们建议使用 静态导入org.springframework.data.mongodb.core.query.Criteria.where和Query.query使查询更具可读性。
查询应返回List或Flux之Person满足指定条件的对象。
本节的其余部分列出了Criteria和Query与 MongoDB 中提供的运算符相对应的类。
大多数方法返回Criteria对象,为 API 提供流畅的样式。
Criteria类的方法
这Criteriaclass 提供了以下方法,所有这些方法都对应于 MongoDB 中的运算符:
-
Criteria都(Object o)使用$all算子 -
Criteria和(String key)添加一个链式的Criteria使用指定的key到当前Criteria并返回新创建的 -
Criteria和运算符(Criteria… criteria)使用$and运算符(需要 MongoDB 2.0 或更高版本) -
Criteria和运算符(Collection<Criteria> criteria)使用$and运算符(需要 MongoDB 2.0 或更高版本) -
Criteriaelem匹配(Criteria c)使用$elemMatch算子 -
Criteria存在(boolean b)使用$exists算子 -
Criteria燃气轮机(Object o)使用$gt算子 -
CriteriaGTE(Object o)使用$gte算子 -
Criteria在(Object… o)使用$invarargs 参数的运算符。 -
Criteria在(Collection<?> collection)使用$in使用集合的运算符 -
Criteria是(Object o)使用字段匹配 ({ key:value }).如果指定的值是文档,则文档中字段的顺序和确切相等性很重要。 -
CriteriaLT(Object o)使用$lt算子 -
CriteriaLTE(Object o)使用$lte算子 -
Criteria国防部(Number value, Number remainder)使用$mod算子 -
CriteriaNE(Object o)使用$ne算子 -
Criteria宁(Object… o)使用$nin算子 -
Criterianor运算符(Criteria… criteria)使用$nor运算符 -
Criterianor运算符(Collection<Criteria> criteria)使用$nor运算符 -
Criteria不 使用()$notmeta 运算符,它影响直接后面的子句 -
Criteria或运算符(Criteria… criteria)使用$or运算符 -
Criteria或运算符(Collection<Criteria> criteria)使用$or运算符 -
Criteria正则表达式(String re)使用$regex -
Criteria采样率(double sampleRate)使用$sampleRate算子 -
Criteria大小(int s)使用$size算子 -
Criteria类型(int t)使用$type算子 -
CriteriamatchingDocumentStructure(MongoJsonSchema schema)使用$jsonSchema运算符。$jsonSchema只能应用于查询的顶层,不能应用于特定于属性。使用properties属性,以与嵌套字段进行匹配。 -
Criteriabits() 是 MongoDB 按位查询运算符的网关,例如$bitsAllClear.
Criteria 类还为地理空间查询提供了以下方法。
-
Criteria在(Circle circle)使用$geoWithin $center运营商。 -
Criteria在(Box box)使用$geoWithin $box操作。 -
Criteria球体内(Circle circle)使用$geoWithin $center运营商。 -
Criteria近(Point point)使用$near操作 -
CriterianearSphere 的(Point point)使用$nearSphere$center操作。这仅适用于 MongoDB 1.7 及更高版本。 -
Criteria最小距离(double minDistance)使用$minDistance作,用于$near。 -
Criteria最大距离(double maxDistance)使用$maxDistance作,用于$near。
这Queryclass 有一些额外的方法,允许选择某些字段以及限制和排序结果。
Query 类的方法
-
Query添加标准(Criteria criteria)用于向查询添加其他条件 -
Field用于定义要包含在查询结果中的字段的字段() -
Query限制(int limit)用于将返回结果的大小限制为提供的限制(用于分页) -
Query跳(int skip)用于跳过结果中提供的文档数(用于分页) -
Query跟(Sort sort)用于为结果提供排序定义 -
Query跟(ScrollPosition position)用于提供滚动位置(基于偏移量或基于键集的分页)以启动或恢复Scroll
模板 API 允许直接使用结果投影,使您能够将查询映射到给定域类型,同时将作结果投影到另一个域类型上,如下所述。
class
template.query(SWCharacter.class)
.as(Jedi.class)
有关结果预测的更多信息,请参阅文档的 预测 部分。
选择字段
MongoDB 支持投影查询返回的字段。
投影可以包含和排除字段(_id字段始终包含在内,除非明确排除),否则。
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 | 结果将包含_id和last_name通过{ "last_name" : 1 }. |
| 2 | 结果将仅包含last_name通过{ "_id" : 0, "last_name" : 1 }. |
| 3 | 结果将包含_id和整个address对象通过{ "address" : 1 }. |
| 4 | 结果将包含_id以及address对象,该对象仅包含city字段通过{ "address.city" : 1 }. |
从 MongoDB 4.4 开始,您可以使用聚合表达式进行字段投影,如下所示:
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应用程序接口
直接有几种方法可用于这些选项。
提示
索引提示可以通过两种方式应用,即使用索引名称或其字段定义。
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);
查询非重复值
MongoDB 提供了一个作,通过使用结果文档中的查询来获取单个字段的不同值。 结果值不需要具有相同的数据类型,该功能也不局限于简单类型。 对于检索,实际结果类型对于转换和键入确实很重要。以下示例演示如何查询非重复值:
template.query(Person.class) (1)
.distinct("lastname") (2)
.all(); (3)
| 1 | 查询Person收集。 |
| 2 | 选择lastname田。字段名称根据域类型属性声明进行映射,获取潜力@Field注释。 |
| 3 | 将所有非重复值检索为List之Object(由于未指定显式结果类型)。 |
将不同值检索到Collection之Object是最灵活的方式,因为它会尝试确定域类型的属性值并将结果转换为所需的类型或映射Document结构。
有时,当所需字段的所有值都固定为某种类型时,直接获取正确键入的Collection,如以下示例所示:
template.query(Person.class) (1)
.distinct("lastname") (2)
.as(String.class) (3)
.all(); (4)
| 1 | 查询Person. |
| 2 | 选择lastname田。fieldname 根据域类型属性声明进行映射,获取潜力@Field注释。 |
| 3 | 检索到的值将转换为所需的目标类型 — 在本例中,String.如果存储的字段包含文档,也可以将值映射到更复杂的类型。 |
| 4 | 将所有非重复值检索为List之String.如果类型无法转换为所需的目标类型,则此方法会抛出DataAccessException. |
+= 地理空间查询
MongoDB 通过使用运算符(例如$near,$within,geoWithin和$nearSphere.特定于地理空间查询的方法可在Criteria类。还有一些形状类(Box,Circle和Point)与地理空间相关Criteria方法。
| 在MongoDB事务中使用GeoSpatial查询时需要注意,请参阅事务中的特殊行为。 |
要了解如何执行地理空间查询,请考虑以下事项Venue类(取自集成测试并依赖于MappingMongoConverter):
Venue.java
@Document(collection="newyork")
public class Venue {
@Id
private String id;
private String name;
private double[] location;
@PersistenceCreator
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 中更改! Spring 数据 MongoDB 2.2 计算的距离( 目标类型可能包含以返回的距离命名的属性,以便(另外)将其直接读回域类型,如下所示。
|
MongoDB 支持查询数据库的地理位置,同时计算与给定原点的距离。通过近地查询,您可以表达诸如“查找周围 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);
我们使用NearQuerybuilder API 来设置查询以返回所有Restaurant给定Point到 10 英里。
这Metrics这里使用的 enum 实际上实现了一个接口,以便其他指标也可以插入距离。
一个Metric由乘数支持,将给定指标的距离值转换为原生距离。
此处显示的示例将 10 视为英里。使用其中一个内置指标(英里和公里)会自动触发要在查询上设置的球形标志。
如果你想避免这种情况,请通过普通double值转换为maxDistance(…). 有关更多信息,请参阅NearQuery和Distance.
地理近距离作返回GeoResults封装GeoResult实例。
包皮GeoResults允许访问所有结果的平均距离。
单GeoResult对象携带找到的实体加上它与原点的距离。
GeoJSON 支持
MongoDB 支持地理空间数据的 GeoJSON 和简单(旧)坐标对。这些格式既可用于存储数据,也可用于查询数据。请参阅有关 GeoJSON 支持的 MongoDB 手册,了解要求和限制。
域类中的 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 类型
使用 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 | 使用 commons 类型的存储库方法定义允许使用 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 格式使用 Meters。 |
为避免严重头痛,请确保将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 ] }
}
从 400 米半径内获取所有文档[-73.99171, 40.738868]使用
地理JSON:
{
"$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 | 距中心点的距离(以米为单位)。 |
现在,当使用传统坐标对时,如前所述,对弧度进行作。所以我们使用Metrics#KILOMETERS
when constructing the `$geoNear命令。这Metric确保距离乘数设置正确。
{
"$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可以按如下方式定义和运行:
Query query = TextQuery
.queryText(new TextCriteria().matchingAny("coffee", "cake"));
List<Document> page = template.find(query, Document.class);
要根据weights用TextQuery.sortByScore.
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\")或使用 byTextCriteria.phrase.以下示例显示了定义短语的两种方法:
// search for phrase 'coffee cake'
TextQuery.queryText(new TextCriteria().matching("\"coffee cake\""));
TextQuery.queryText(new TextCriteria().phrase("coffee cake"));
您可以为$caseSensitive和$diacriticSensitive通过使用TextCriteria. 请注意,这两个可选标志已在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,则可以绕过默认行为并跳过类型限制。因此,只要字段名称匹配,几乎任何域类型都可以用作创建引用的探测,如以下示例所示:
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);
|
当包括 |
|
另外,请记住,使用 |
Spring Data MongoDB 提供了对不同匹配选项的支持:
StringMatcher选项
| 匹配 | 逻辑结果 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
查询集合以匹配 JSON 架构
可以使用架构查询任何集合,以查找与 JSON 架构定义的给定结构匹配的文档,如以下示例所示:
$jsonSchemaMongoJsonSchema schema = MongoJsonSchema.builder().required("firstname", "lastname").build();
template.find(query(matchingDocumentStructure(schema)), Person.class);
请参阅 JSON Schema 部分以了解有关 Spring Data MongoDB 中的 Schema 支持的更多信息。