MongoDB: как я могу заказать по расстоянию, учитывая несколько полей?


У меня есть коллекция, в которой хранится информация о врачах. Каждый врач может работать в частной практике и / или в больницах. Коллекция имеет следующие соответствующие поля (имеются геопространственные индексы на обеих частных практиках.адрес.Лок и больницы.адрес.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. Является это возможно сделать в монго?

EDIT-прикладное решение (MongoDB 2.6): Я использовал свой собственный подход, вдохновленный тем, что предлагает Нил Ланн в своем ответе: я добавил поле в документе доктора для сортировки, содержащее массив со всеми местоположениями доктора.

Я попробовал этот подход в MongoDB 2.4 и MongoDB 2.6, и результаты разные. Запросы на 2.4 возвращали дубликаты докторов, у которых было больше, чем местоположение, даже если _id был включен в запрос фильтр. Запросы на 2.6 возвращали корректные результаты.

1 2

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 и приведет к тому, что вы примените математику самостоятельно при обработке результатов.