当前文档字段值内的地理空间 $near

Geospatial $near within current document field value

接受这个查询:

{ 'location' : { '$near' : [x,y], '$maxDistance' : this.field } }

我想为 $maxDistance 分配当前评估文档中指定字段的值。那可能吗?

是的,这是可能的。您只需使用 $geoNear 即可。当心陷阱并仔细阅读。

假设您的意图是存储一个字段,例如 "travelDistance" 以在文档上指示任何此类搜索必须 "within" 提供距查询点的距离才有效。然后我们简单地查询和评估条件 $redact:

db.collection.aggregate([
  { "$geoNear": {
    "near": { 
      "type": "Point",
      "coordinates": [x,y]
    },
    "spherical": true,
    "distanceField": "distance"
  }},
  { "$redact": {
    "$cond": {
      "if": { "$lte": [ "$distance", "$travelDistance" ] },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

唯一的问题是 $geoNear 就像 $near 只会 return 一定数量的文档 "near"第一名。您可以使用选项对其进行调整,但与一般查询表单不同,这基本上保证了最终 returned 结果将小于指定的 "nearest" 数字。

只要你知道这一点,那么这就是完全正确的。

这实际上是处理半径范围内 "near" 的一般方法。

还要注意 "distance" 根据您的坐标存储方式。作为传统坐标对,距离将以弧度为单位,您可能需要进行数学运算才能将其转换为千米或英里。

如果使用 GeoJSON,则距离始终以米为单位,作为标准格式。

所有数学笔记都在文档中。

N.B Read the $geoNear documentation carefully. Options like "spherical" are required for "2dsphere" indexes, such as you should have for real world coordinates. Also "limit" may need to be applied to increase past the default 100 document result, for further trimming.


正如评论中提到的 spring mongo,那么这基本上是相同的事情:

Aggregation aggregation = newAggregation(
    new AggregationOperation() {
      @Override
      public DBObject toDBObject(AggregationOperationContext context) {
        return new BasicDBObject("$geoNear",
          new BasicDBObject(
            "near", new BasicDBObject(
              "type","Point")
              .append("coordinates", Arrays.asList(20,30))
            )
            .append("spherical",true)
            .append("distanceField","distance")
          );
        }
    },
    new AggregationOperation() {
      @Override
      public DBObject toDBObject(AggregationOperationContext context) {
        return new BasicDBObject("$redact",
          new BasicDBObject(
            "$cond", Arrays.asList(
               new BasicDBObject("$lte", Arrays.asList("$distance", "$travelDistance")),
               "$$KEEP",
               "$$PRUNE"
             )
          )
       );
     }
    }
);