Запрос MongoDB поблизости

#mongodb #mongodb-query #geolocation #aggregation-framework

#mongodb #mongodb-запрос #геолокация #агрегация-фреймворк

Вопрос:

У меня есть пользователь коллекции, рестораны, продукты, которые я хочу запросить, этот пользователь увидит в своем приложении близлежащие рестораны (5 км), которые открыты: true, и покажет продукты каждого ресторана, которые доступны и одобрены = true и архивированы: false.

 let kmToRadian = function(miles){
 var earthRadiusInMiles = 6378
 return miles / earthRadiusInMiles
}

var user = dbo.collection('users').findOne({_id: id})
var query = {
  "location": {
      $geoWithin: {
          $centerSphere: [ [22.222, 22.222], 5 / 6378.1] //sample coordinates
      }
  }
}


db.products.aggregate([
    { 
        $lookup: { 
            from: "restaurants", 
            localField: "restaurants", 
            foreignField: "_id", 
            as: "restaurant" 
        } 
    },
    {
        $match : {
            "restaurant.isOpen": true,
            "isApproved": true,
            "isAvailable": true,
            "isArchived": false
        }
    },
    {
        $project: {
            "restaurant.isOpen": 1,
            "isApproved": 1,
            "isAvailable": 1,
            "isArchived": 1,
            "name": 1
        } 
    }
])
 

Здесь я получаю продукты isAvailable, IsApproved :true и IsArchived false . Теперь я хочу получить ресторан в 5 км поблизости.

Пользователи коллекции

 id: 1
name: "Robert"
location: Object
    type: "Point",
    coordinates: Array
     0: 11.111 //sample coordinates
     1: 11.111 //sample coordinates

id: 2
    name: "Jason"
    location: Object
        type: "Point",
        coordinates: Array
         0: 22.222 //sample coordinates
         1: 22.222 //sample coordinates
 

Коллекция ресторанов

 id: 1  
name: "Burger King"
location: Object
    type: "Point",
    coordinates: Array
       0: 11.111 //sample coordinates
       1: 11.111 //sample coordinates
isOpen: true

id: 2
name: "McDonald's"
location: Object
    type: "Point",
    coordinates: Array
       0: 22.222 //sample coordinates
       1: 22.222 //sample coordinates
isOpen: true

id: 3  
name: "Chick-fil-A"
location: Object
    type: "Point",
    coordinates: Array
       0: 22.333 //sample coordinates
       1: 22.333 //sample coordinates
isOpen: true
 

Коллекционные Продукты

 id: 1
name: "Breakfast Whopper Jr."
price: "$1.29"
isAvailable: true
isApproved: true
createdAt: Tues Dec 01 2020 09:15:19 GMT 0800
updatedAt: Tues Dec 01 2020 09:15:19 GMT 0800
isArchived: false
shop: ObjectId('1')

id: 2
name: "Big Mac"
price: "$4.35"
isAvailable: true
isApproved: true
createdAt: Tues Dec 01 2020 09:15:19 GMT 0800
updatedAt: Tues Dec 01 2020 09:15:19 GMT 0800
isArchived: false
shop: ObjectId('2')

id: 3
name: "Spicy Chicken Sandwich"
price: "$3.29"
isAvailable: true
isApproved: true
createdAt: Tues Dec 01 2020 09:15:19 GMT 0800
updatedAt: Tues Dec 01 2020 09:15:19 GMT 0800
isArchived: false
restaurant: ObjectId('3')
 

Выходной сигнал:
если Роберт находится в координатах [ 22.222, 22.222].
Роберт увидит рестораны McDonald’s и Chick-fil-A, потому что isOpen: правда.
Покажите их продукты, такие как Биг Мак и сэндвич с пряной курицей, потому что isAvailable, IsApproved: true и IsArchived: false.

Комментарии:

1. @Minsky Привет, могу ли я получить предложения о том, что использовать для этого типа запросов.

2. db.products.aggregate([ { $lookup: { from: 'restaurants', localField: 'restaurants', foreignField: '_id', as: 'shop' }, }, { $match: { 'restaurant.isOpen': true } } ]) Следующее, что я хочу получить, это доступные и одобренные продукты ресторана, которые являются true, а IsArchived — false. Я все делаю правильно? @Minsky

Ответ №1:

Не ответ, просто некоторые идеи, которые вы должны оценить самостоятельно. Следующий конвейер:

  1. Соответствует isApproved:true, isAvailable:true, isArchived:true , поэтому он предполагает и предлагает использовать этот индекс:
 db.products.createIndex({
  isAvailable: 1, isApproved: 1, isArchived: 1
})
 
  1. Как только количество документов будет хорошо сужено, поиск не должен занимать так много времени. Здесь индекс не требуется, пока foreignField:_id используется, в противном случае я бы создал индекс для этого поля.
  2. Сопоставление $ isOpen:true будет медленным, но позже улучшит производительность, если это сработает. pipeline это $lookup может помочь повысить производительность, добавив этот индекс (ИМХО) db.restaurants.createIndex({ _id: 1, isOpen: 1 })
  3. Я прокомментировал поля, которые мы отфильтровываем в match, потому что мы знаем значение и можем быть установлены, что, вероятно, повышает производительность (не могу это доказать).
  4. Мы проецируем location , потому что нам нужно это поле
  5. Используйте geo, чтобы найти то, что находится рядом, это было почти правильно. Этот шаг будет довольно медленным, потому что в «geo» нет индекса, и создать его в этом запросе невозможно.
 db.products.aggregate([
  {
    $match: {
      "isApproved": true,
      "isAvailable": true,
      "isArchived": false
    }
  },
  {
    $lookup: {
      from: "restaurants",
      foreignField: "_id",
      localField: "restaurant",
      as: "restaurant"
    }
  },
  {
    $match: {
      "restaurant.isOpen": true
    }
  },
  {
    $project: {
      "restaurant.isOpen": 1,
      //"isApproved": 1,
      //"isAvailable": 1,
      //"isArchived": 1,
      "name": 1,
      "restaurant.location": 1
    }
  },
  {
    $match: {
      "restaurant.location": {
        $geoWithin: {
          $centerSphere: [
            [
              22.222,
              22.222
            ],
            5/6378.1] 
      }
  }
  }}
])
 

Я должен сказать, что я не эксперт, так что вам решать тестировать и улучшать. Кроме того, пожалуйста, включайте только формат документов JSON, чтобы мы могли сразу протестировать. Мне пришлось сделать это вручную для ТЕКУЩЕЙ ВЕРСИИ.

(Также полезно помнить, что что-то не очень полезное, но быстрое и хорошо завершенное лучше, чем очень сложное лаговое приложение. Опять же, вы узнаете, как это работает, и я совсем не эксперт. )

Комментарии:

1. Привет, @Minsky извините за поздний ответ. Он не вернул мне рестораны, которые находятся рядом с бездействием. он возвращает мне пустой массив.