0

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

集合中的条目示例:

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

4

2 回答 2

4

您将无法使用普通查询执行此操作,因为您无法动态设置每个文档的距离。从 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 - 抢。

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

于 2013-03-21T03:20:38.867 回答
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);
}

}
于 2014-05-26T13:02:46.520 回答