为什么在使用C#驱动程序的类型化方法时会得到有效但不准确的$ nearSphere查询?

时间:2018-08-23 14:13:22

标签: c# mongodb geospatial mongodb-.net-driver

我正在尝试对我在MongoDB中的文档集合执行$nearSphere查询。在了解调用以类型化方式生成查询的特定方法之前,我使用了以下字符串插值法来自己创建查询,具体方法请参见在线文档:

var query = _col.Find($"{{ location: {{ $nearSphere: {{ $geometry: {{ type: \"Point\", coordinates: [ {lon}, {lat} ] }}, $maxDistance: {rad} }} }} }}");

这很好。我的查询是准确的。但是,在任何可能的地方,我都想改用类型化的方法,以便将来编译器为我提供帮助。因此,我在网上寻找了如何进行编码的方法,在阅读了之前的StackOverflow答案后,我想到了这个方法: / p>

var filter = Builders<Node>.Filter.NearSphere(n => n.Location, lon, lat, rad);
var query2 = _col.Find<Node>(filter);

问题在于,它们在后台生成了不同的查询,而后者生成的查询是不准确的。还有很多要点。

通过对生成的查询调用.ToString(),我发现第一个查询变成了...

{find({ "location" : { "$nearSphere" : { "$geometry" : { "type" : "Point", "coordinates" : [1, 2] }, "$maxDistance" : 3 } } })}

...产生准确的结果。

第二个变成...

{find({ "location" : { "$nearSphere" : [1.0, 2.0], "$maxDistance" : 3.0 } })}

...格式不同,但无法产生准确的结果。

请注意,这里用于表示经度,纬度和半径的数字是示例,我的应用使用了我所在区域的实际值,可以通过检查OpenStreetMap数据进行确认。

1 个答案:

答案 0 :(得分:0)

最终我自己解决了这个问题,将更多的时间花在了文档上并花了很多时间直到编译它。我发现很难在文档中找到解决方案,因为除了一小部分关于目前不支持地理空间查询与LINQ的内容外,他们没有执行地理空间查询的示例。

使用C#驱动程序的版本2.7执行此类查询的代码为:

var filterPoint = GeoJson.Point(new GeoJson2DCoordinates(lon, lat));

var filter = new FilterDefinitionBuilder<Node>()
             .NearSphere(n => n.Location, filterPoint, rad);

var query = _col.Find<Node>(filter);

我还必须确保我在模型(用于执行查询的类)中使用了MongoDB GeoJSON点数据类型:

public class Node
{
    [BsonElement("_id")]
    public long Id { get; set; }

    [BsonElement("location")]
    public GeoJsonPoint<GeoJson2DCoordinates> Location { get; set; }

    [BsonElement("tags")]
    public BsonDocument Tags { get; set; }
}

请注意,Tags属性代表任何JSON类型,因此我使用BsonDocument。返回响应后,我可以将其映射到Dictionary<string, object

仅是为了向阅读本文的任何人提供一个更完整的示例,这是我在准备运行查询后将其使用,将结果映射到我的DTO并在ASP.NET Core 2.1中发送200响应后使用的代码: / p>

// Perform query and map to DTO
var res = (await query.ToListAsync()).Select(n =>
{
    var lonLat = n.Location.Coordinates.Values.ToArray();

    return new NodeBase
    {
        Id = n.Id.ToString(),
        Location = new SimpleGeoJsonPoint
        {
            Lon = lonLat[0],
            Lat = lonLat[1],
        },
        Tags = n.Tags.ToDictionary(),
    };
});

return Ok(new MultiSearchResult<NodeBase>
{
    Count = res.Count(),
    Results = res,
});

请注意,NodeBase是我的DTO,用于在我的Node文档执行搜索时将其返回给客户端。 SimpleGeoJsonPoint是我在其他DTO中使用的DTO,用于以简单的方式表示GeoJSON点。我不需要绒毛,只有经度和纬度。 MultiSearchResult<T>是我的通用DTO,用于将搜索结果返回给客户端。