2013-03-20 60 views
0

我想执行一个查询,其中距离是集合中的动态字段。MongoDb near /可变距离的geonear查询

集合中条目的示例:

{ 
    name:'myName', 
    location: {lat:10, lng:20}, 
    maximumDistance: 10 
} 
{ 
    name:'myName2', 
    location: {lat:20, lng:20}, 
    maximumDistance: 100 
} 

我的目标是获取所有从这个集合,其中该位置接近给定位置的元素,比方说(10,10),但其中计算的距离小于这个最大距离字段的

我可以在近查询中将maxDistance设置为一个常量值(足够高以检索我想要的所有元素),然后在我的java代码中执行过滤器,但是我希望在查询时也可以这样做SQL为导向。

回答

4

由于无法动态设置每个文档的距离,因此您将无法使用普通查询执行此操作。从MongoDB 2.4开始,您可以使用聚合框架来完成此任务,因为它们已将geoNear运算符添加到流水线开始处。

第一阶段将是与geonear命令非常相似的geoNear。因此,我们还将获得从指定点(10,10)到文档的距离。

第二阶段我们将需要使用项目操作员来添加maximumDistance字段和计算出的地理距离之间的差异。

最后,我们匹配那些有正值的文件((最大距离)> 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 - 罗布。

P.S.上面的建设者正在使用该驱动程序的1.2.0版本的预发行版本。代码正在通过构建矩阵输入,并将于2013年3月22日星期五发布。

+0

非常感谢这个非常详细的答案。听起来和我需要的完全一样,我现在试着弄清楚我是否可以用Spring Data - MongoDb做同样的事情 – 2013-03-21 04:06:09

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

} 
相关问题