MongoDb附近/ geonear查询可变距离

时间:2013-03-20 22:31:34

标签: mongodb geolocation

我想执行一个查询,其中距离是集合中的动态字段。

集合中的条目示例:

{
  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导向。

2 个答案:

答案 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);
}

}