MongoDB:考虑到多个字段,我如何按距离排序?

Posted

技术标签:

【中文标题】MongoDB:考虑到多个字段,我如何按距离排序?【英文标题】:MongoDB: How can I order by distance considering multiple fields? 【发布时间】:2014-08-31 13:58:40 【问题描述】:

我有一个存储医生信息的集合。每个医生都可以在私人诊所和/或医院工作。 该集合具有以下相关字段(privatePractices.address.loc 和 hospital.address.loc 都有地理空间索引):


  "name" : "myName",
  "privatePractices" : [
      "_id": 1,
      "address" : 
        "loc" : 
          "lng" : 2.1608502864837646,
          "lat" : 41.3943977355957
        
      
    ,
    ...
    ],
  "hospitals" : [
      "_id": 5,
      "address" : 
        "loc" : 
          "lng" : 2.8192520141601562,
          "lat" : 41.97784423828125
        
      
    ,
    ...
    ]

我正在尝试查询该集合以获取按与给定点的距离排序的医生列表。这就是我卡住的地方:

以下查询返回按距离到 $nearSphere 中定义的点的距离排序的医生列表,仅考虑两种位置类型之一:

 "hospitals.address.loc" :  "$nearSphere" : [2.1933, 41.4008]  
 "privatePractices.address.loc" :  "$nearSphere" : [2.1933, 41.4008]  

我想要的是让最近的医院或私人诊所订购的医生,无论是最近的。是否可以在单个 Mongo 查询中执行此操作?

B 计划是使用上面的查询,然后在 Mongo 之外手动排序结果(例如,使用 Linq)。为此,我的两个查询应返回每家医院或私人诊所到 $nearSphere 点的距离。是否可以在 Mongo 中做到这一点?

编辑 - 应用解决方案 (MongoDB 2.6): 受 Neil Lunn 在他的回答中建议的启发,我采用了自己的方法:我在 Doctor 文档中添加了一个字段用于排序目的,其中包含一个包含医生所有位置的数组。

我在 MongoDB 2.4 和 MongoDB 2.6 中尝试过这种方法,结果不同。 2.4 上的查询返回了具有多个位置的重复医生,即使 _id 包含在查询过滤器中。对 2.6 的查询返回有效结果。

【问题讨论】:

建模是这里的问题,因为这个不会为您的预期目的而削减它。也许最好的回答方法是真正了解“找医生”的意思。是否有任何特定的选择标准适用于这些医生?例如特定的“专家类型”或其他东西。我通常认为这里的计划 C 会比您的计划 B 执行得更好 我在某些情况下使用其他条件进行查询,但我通常也希望按邻近度排序结果。我对你的 C 计划很感兴趣——那会是什么? @ederbf 您使用“多点”索引还是仅使用“点”?你能分享你的最终文档架构吗? @Zyoo,你说的“多点”是什么意思?我知道的唯一球形指数是“2dsphere”,这就是我使用的。我的解决方案最终与 Neil Lunn 在他的回答中建议的非常相似,他的架构就是一个很好的例子 :) 我的意思是geojson类型。最后我用“MultiPoint”保存多个位置,然后通过“Point”查询。类似于***.com/questions/31295049/… 【参考方案1】:

我本来希望在这里获得更多信息,但基本知识仍然适用。因此,您偶然发现的一般问题是试图在您的医生文件上设置“两个”位置字段。

这种方法还有另一个问题。您的文档中的数组中有“位置”/ 这在创建索引时不会给您一个错误,但它也不会像您期望的那样工作。这里最大的问题是,在数组中,您可能会找到“包含”最近位置的文档,但问题是“哪个”,因为没有做任何事情来影响数组内容。

核心问题是每个查询不能有多个地理空间索引。但要真正得到你想要的,把问题放在头上,基本上把医生安排到这些地方,这是相反的。

例如这里,一个“实践”集合之类的:


    "type": "Hospital",
    "address" : 
        "loc" : 
          "lng" : 2.8192520141601562,
          "lat" : 41.97784423828125
        
    ,
    "doctors": [
         "_id": 1, "name": "doc1", "specialty": "bones" ,
         "_id": 2, "name": "doc2", "specialty": "heart"        
    ]



    "type": "Private",
    "address" : 
       "loc" : 
          "lng" : 2.1608502864837646,
          "lat" : 41.3943977355957
       
    ,
    "doctors": [
         "_id": 1, "name": "doc1", "specialty": "bones" ,
         "_id": 3, "name": "doc3", "specialty": "brain" 
    ]

这里的优势在于,作为一个集合并且全部在同一个索引中,您可以简单地获得两个“类型”,并按距离或范围内或您需要的任何地理查询正确排序。这样就避免了其他建模形式的问题。

至于“医生”信息,当然,您实际上自己为完整的医生信息保留了一个单独的集合,甚至可能还为位置文档保留了一组 _id 值。但这里的要点是,您通常可以在此处将一些有用的搜索信息“嵌入”到一个集合中,这将对您有所帮助。

这似乎是更好的选择,并且可以将医生与该位置内部的条件进行匹配,而在数组中查找或排序最近的条目是 MongoDB 不支持的本身,并且会导致您自己在处理结果时应用数学。

【讨论】:

我明白你的意思,这绝对是一种有效的方法。以您的解决方案为灵感,我最终可能会做相反的事情:在医生文档中添加一个“位置”字段,在一个数组中包含一位医生的所有 loc 信息。 @ederbf 了解我在此处开头所说的内容,在嵌入式数组中搜索地理位置并不会为您提供您认为的结果。我曾建议过一个类似的案例,有人试图以这种方式将“商店”的“出口”存储在数组中。我认为你最好按照描述的那样做。您对医生的“搜索关键字”不太可能经常更改,更新这些关键字相当简单。仅就数据大小而言,这提供了最少程度的重复。 好的,我将测试这两个选项并比较结果 - 稍后会返回结果。谢谢! 我已经用我最终实施的解决方案更新了我的问题。嵌入式数组中的 Geoloc 搜索在 MongoDB 2.4 中确实给出了意外的结果,但这似乎已在 MongoDB 2.6 中得到纠正。我这样做是因为重复的水平较低。我最终可能会将私人和医院存储在同一个子文档下并添加“类型”字段。但是为此需要一个大的重构,所以它超出了这个问题的范围。最后但并非最不重要的一点 - 我接受你的回答,因为它引导我朝着正确的方向前进。

以上是关于MongoDB:考虑到多个字段,我如何按距离排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 mongoDb 中按多个字段排序

使用mongoose在mongodb中按升序和降序对多个字段进行排序

使用多个字段在 MongoDB 聚合框架中按相关性排序

使用多个字段在 MongoDB 聚合框架中按相关性排序

MongoDB v2.4.9 按布尔字段排序

MongoDB v2.4.9 按布尔字段排序