如何对嵌入式文档进行 $geoNear 聚合?

Posted

技术标签:

【中文标题】如何对嵌入式文档进行 $geoNear 聚合?【英文标题】:How can I do a $geoNear aggregation on embedded documents? 【发布时间】:2020-10-02 10:44:24 【问题描述】:

我有一个名为 services 的 MongoDB 集合,每个集合都有多个嵌入位置。

看起来像这样:


  name: "example",
  locations: [
    
      coordinates: [0, 0] 
    ,
    
      coordinates: [0, 0] 
    ,
  ]

我想对 $unwind 数据结构使用聚合,因此每个位置都被视为单独的文档,然后使用 $geoNear 根据与用户提供的点的距离对每个位置进行排序,如下所示:

db.collection("services").aggregate([
   $unwind : "$locations" 
   $geoNear: 
    near: [0, 0],
    distanceField: "distance"
  ,

不过,很自然,$geoNear 想成为first thing in an aggregation,我很难理解如果没有 $unwind 先出现它是如何工作的。

创建索引 似乎 成功,但是当我尝试运行它时,我收到“无法找到 $geoNear 查询的索引”错误。

我能否以某种方式运行一个聚合,然后对结果运行另一个聚合?

或者,有没有办法在没有聚合的情况下做到这一点?

重要的是,简单地更改数据架构并不容易,因为 mongo 被用作搜索索引之类的东西,而数据本身来自其他地方的关系数据库。

我或许可以考虑创建第二个预展开数据的集合? MongoDB 是否有某种回调可以减轻这种痛苦?

【问题讨论】:

【参考方案1】:

geoNear 查询需要特殊的 2d 或 2dsphere 索引。索引会将每个位置与文档相关联。如果单个文档包含多个位置,则所有位置都将引用同一个文档。

geoNear 查询然后通过搜索索引选择文档,并按从最近到最远的顺序返回文档。

单个文档即使有多个位置也不会被多次返回。

虽然展开确实允许您处理单独文档中的每个位置,但在 $unwind 之后管道中的文档没有索引,因此 geoNear 无法运行。

使用 geoNear 检查数组中所有元素的唯一方法是在展开后将它们输出到临时集合,在临时集合上创建 2dsphere 索引,然后将 geoNear 与该集合一起使用。

您可以使用Haversine 公式计算两点之间距离的合理近似值。

【讨论】:

以上是关于如何对嵌入式文档进行 $geoNear 聚合?的主要内容,如果未能解决你的问题,请参考以下文章

使用 geonear 的 Mongoose 聚合

MongoDB/Mongoose - 与 geoNear 和子文档的聚合

MongoDB GeoNear 聚合

如何通过 Mongoose 查询对嵌入文档数组进行排序?

GraphQL和MongoDB` $ geoNear`聚合

计算嵌入文档/数组中字段的平均值