我想执行一个查询,其中距离是集合中的动态字段。
集合中的条目示例:
{
name:'myName',
location: {lat:10, lng:20},
maximumDistance: 10
}
{
name:'myName2',
location: {lat:20, lng:20},
maximumDistance: 100
}
我的目标是从此集合中检索此位置靠近给定位置的所有元素,假设(10,10)但计算距离小于此 maximumDistance 字段。
我可以在near查询中将maxDistance设置为常量值(足够高以检索我想要的所有元素),然后在我的java代码中执行过滤,但我更喜欢在查询中执行它可能也是SQL导向。
答案 0 :(得分:4)
您无法使用普通查询执行此操作,因为您无法动态设置每个文档的距离。从MongoDB 2.4开始,您可以使用聚合框架执行此操作,因为他们已将geoNear运算符添加到管道的起点。
第一阶段是geoNear,它与geonear命令非常相似。我们还将获得从指定点(10,10)到文档的距离。
在第二阶段,我们需要使用项目运算符来区分maximumDistance字段和计算的geoNear距离之间的差异。
最后,我们匹配那些具有正增量((最大 - 距离)> 0)的文档。
以下是使用Asynchronous Java Driver帮助程序类的管道。
package example;
import static com.allanbank.mongodb.builder.AggregationProjectFields.include;
import static com.allanbank.mongodb.builder.QueryBuilder.where;
import static com.allanbank.mongodb.builder.expression.Expressions.field;
import static com.allanbank.mongodb.builder.expression.Expressions.set;
import static com.allanbank.mongodb.builder.expression.Expressions.subtract;
import com.allanbank.mongodb.bson.element.ArrayElement;
import com.allanbank.mongodb.builder.Aggregate;
import com.allanbank.mongodb.builder.AggregationGeoNear;
import com.allanbank.mongodb.builder.GeoJson;
public class AggregateGeoNear {
public static void main(String[] args) {
Aggregate aggregate = Aggregate
.builder()
.geoNear(
AggregationGeoNear.builder()
.location(GeoJson.p(10, 10))
.distanceField("distance"))
.project(
include("name", "location", "maximumDistance"),
set("delta",
subtract(field("maximumDistance"),
field("distance"))))
.match(where("delta").greaterThanOrEqualTo(0)).build();
System.out
.println(new ArrayElement("pipeline", aggregate.getPipeline()));
}
}
这是管道创建:
pipeline : [
{
'$geoNear' : {
near : [
10,
10
],
distanceField : 'distance',
spherical : false,
uniqueDocs : true
}
},
{
'$project' : {
name : 1,
location : 1,
maximumDistance : 1,
delta : {
'$subtract' : [
'$maximumDistance',
'$distance'
]
}
}
},
{
'$match' : {
delta : { '$gte' : 0 }
}
}
]
HTH - Rob。
P.S。上面的构建器正在使用1.2.0版驱动程序的预发行版。我输入时代码将通过构建矩阵,并应在2013年3月22日星期五之前发布。
答案 1 :(得分:1)
关于如何使用Spring Data解决它,我已经通过构建新的GeoNearOperation实现来解决它,因为它必须在投影中包含maxDistance字段名称:
public class GeoNearOperation2 implements AggregationOperation {
private NearQuery nearQuery;
public GeoNearOperation2(NearQuery nearQuery) {
this.nearQuery = nearQuery;
}
public DBObject toDBObject(AggregationOperationContext context) {
DBObject dbObject = context.getMappedObject(nearQuery.toDBObject());
dbObject.put("distanceField", "distance");
return new BasicDBObject("$geoNear",dbObject);
}
}