【问题标题】:MongoDb near/geonear query with variable distance具有可变距离的 MongoDb 近/近地查询
【发布时间】:2013-03-20 22:31:33
【问题描述】:

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

集合中的条目示例:

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

我的目标是从该集合中检索此 位置 靠近给定位置的所有元素,例如 (10,10) 但计算出的距离小于此 最大距离 字段。

我可以在 near 查询中将 maxDistance 设置为一个常量值(足够高以检索我想要的所有元素),然后在我的 java 代码中进行过滤,但我更愿意在查询中执行它可能太 SQL导向的。

【问题讨论】:

    标签: mongodb geolocation


    【解决方案1】:

    您无法使用普通查询执行此操作,因为您无法动态设置每个文档的距离。从 MongoDB 2.4 开始,您可以使用聚合框架执行此操作,因为它们已将 geoNear 运算符添加到管道的开头。

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

    第二阶段,我们将需要使用项目运算符来广告 maximumDistance 字段和计算的 geoNear 距离之间的差异。

    最后,我们匹配那些具有正 delta ((max - distance) > 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 - 抢劫。

    附:上面的构建器使用的是 1.2.0 版本的驱动程序的预发布版本。在我输入代码时,代码正在通过构建矩阵,应该会在 2013 年 3 月 22 日星期五之前发布。

    【讨论】:

    • 非常感谢这个非常详细的回答。听起来完全符合我的需要,我现在将尝试弄清楚是否可以对 Spring Data - MongoDb 做同样的事情
    【解决方案2】:

    关于如何使用 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);
    }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      • 1970-01-01
      • 2017-10-05
      • 1970-01-01
      • 2017-06-25
      相关资源
      最近更新 更多