$geowithin:$polygon 不使用 2dsphere 索引

$geowithin:$polygon doesn't use 2dsphere index

我收集了如下文件:

{
    "_id" : ObjectId("5bc15f23d672e9086ca4fbac"),
    "Location" : {
        "GeoJson" : {
            "type" : "Point",
            "coordinates" : [14.4199254356, 50.0700249768]
        }
}

我创建的索引如下

{ Location.GeoJson2dsphere : "2dsphere" }

现在,当我使用 $polygon 进行搜索时出现问题,我得到了结果,但是查询没有使用索引,所以速度很慢。这是查询

.find({"Location.GeoJson" : {
      "$geoWithin" : {
      "$polygon" : [ 
        [14.4182910543168, 50.0891393887804], 
        [14.4491901021683, 50.0891393887804], 
        [14.4491901021683, 50.0671069088523], 
        [14.4182910543168, 50.0671069088523]
      ]
    }
  }
})

但是当我改用 $Geometry 时,它使用的是索引。

.find({"Location.GeoJson" : {
  "$geoWithin" : 
    {"$geometry" :
      {"type" : "Polygon",
        "coordinates" : [[ 
          [14.4182910543168, 50.0891393887804], 
          [14.4491901021683, 50.0891393887804], 
          [14.4491901021683, 50.0671069088523], 
          [14.4182910543168, 50.0671069088523],
          [14.4182910543168, 50.0891393887804]
        ]]
      }}
    }})

第一个查询没有使用索引有什么原因吗? Mongo 手册对此没有任何说明。 你能告诉我,如何使用 $polygon 搜索索引,还是我需要重写我应用程序中的所有查询,才能使用 $geometry.我正在使用语法如下所示的 C# 驱动程序:

Builders<Offer>.Filter.GeoWithinPolygon(a => a.Location.GeoJson, polygon);

但是,这是生成第一个查询,它没有使用索引。

我不为 mongo 工作,所以不会冒险猜测 为什么 (超越旧数据模型与新数据模型)让新手感到困惑,但这是 如何 mongo 区分 infinite-flat-2d ($polygon query) 索引和一个 spherical 索引 ($geometry query)

传递 $polygon 以遗留二维索引为目标,其中 $geometry 以二维球面索引为目标。 Mongo 将这些查询拆分为两种不同的对象类型

此处:https://github.com/mongodb/mongo/blob/master/src/mongo/db/geo/geoparser.cpp#L785-L790

Mongo 确实说 2dsphere 索引 可通过 $geometry 查询访问(不是遗留 $多边形查询)

此处:https://docs.mongodb.com/manual/tutorial/query-a-2dsphere-index/

如您所述: Mongo 非常有用,因为它仍然可以 return 数据,即使如果您的查询不匹配。


为什么 $polygon 不再是一个东西了?

Mongo 继续为那些希望在无限平面上使用二维索引的用户提供非球形二维索引支持。也许对于视频游戏或任何使用无限平面是足够好的近似以避免浮点数学(和相关的舍入问题)

此处描述:https://docs.mongodb.com/manual/tutorial/query-a-2d-index/

好的,我只是用 C# 添加答案。

新查询是:

GeoJsonPolygon<GeoJson2DCoordinates> polygon;
var filter = Builders<Offer>.Filter.GeoWithin(a => a.Location.GeoJson, polygon);

还有我的帮手 class rectangle.ToGeoJsonPolygon():

public class Rectangle
    {
        public double StartX { get; set; }
        public double StartY { get; set; }
        public double EndX { get; set; }
        public double EndY { get; set; }

        public double[,] ToCoordinates()
        {
            var retval = new double[4, 2];
            retval[0, 0] = this.StartX;
            retval[0, 1] = this.StartY;
            retval[1, 0] = this.EndX;
            retval[1, 1] = this.StartY;
            retval[2, 0] = this.EndX;
            retval[2, 1] = this.EndY;
            retval[3, 0] = this.StartX;
            retval[3, 1] = this.EndY;

            return retval;
        }

        public GeoJsonPolygon<GeoJson2DCoordinates> ToGeoJsonPolygon()
        {
            return GeoJson.Polygon(
                GeoJson.Position(StartX, StartY),
                GeoJson.Position(EndX, StartY),
                GeoJson.Position(EndX, EndY),
                GeoJson.Position(StartX, EndY),
                GeoJson.Position(StartX, StartY));
        }
    }