Как группировать по геопространственному атрибуту в mongodb?

#mongodb #aggregation-framework

#mongodb #структура агрегации

Вопрос:

У меня есть набор документов в mongodb, и я пытаюсь сгруппировать набор документов, используя ближайшие координаты геопункта на расстоянии 100 м в радиусе до данного документа, и получить среднее значение type и $first значение для cordinates . Образец набора документов приведен ниже. Есть ли способ сделать это, используя существующие функции в конвейере агрегации mongodb, или мне нужно использовать недавно введенные $function для создания пользовательской функции агрегации. Любые предложения приветствуются.

 {"_id":{"$oid":"5e790cfe46fa8260f41d2626"},
  "cordinates":[103.96277219999999,1.3437526],
  "timestamp":1584991486436,
  "user":{"$oid":"5e4bbbc31eac8e2e3ca219a6"},
  "type": 1,
  "__v":0}

{"_id":{"$oid":"5e790d7346fa8260f41d2627"},
  "cordinates":[103.97242539965999,1.33508],
  "timestamp":1584991603400,
  "user":{"$oid":"5e4bbbc31eac8e2e3ca219a6"},
  "type": 1,
  "__v":0}

 {"_id":{"$oid":"5e790d7346fa8260f41d2627"},
  "cordinates":[103.97242539990099,1.33518],
  "timestamp":1584991603487,
  "user":{"$oid":"5e4bbbc31eac8e2e3ca219a6"},
  "type": 2,
  "__v":0}
  

Образец документа, который ожидается в качестве вывода после конвейера агрегации.

  {"avgCordinates":[103.97242539990099,1.33518],
  "avgType": 1.6,
 }
 
  

Ответ №1:

Мне удалось решить эту проблему, создав пользовательскую функцию для представления одного значения для геопространственной координаты, а затем сгруппировав по возвращаемым значениям. Я смог сгруппировать близлежащие координаты в один документ, поскольку функция, которую я использовал для преобразования значений, также будет сопоставляться с близлежащими скалярными значениями. До сих пор это давало мне ожидаемые результаты для тепловой карты. Но все же я не уверен, что это правильный способ сделать это. Для этого должен быть лучший ответ. Я опубликовал свой конвейер агрегации ниже. Приветствуются любые предложения по улучшению этого.

 [
  {
    '$match': {
      'timestamp': {
        '$gte': 1599889338000
      }
    }
  }, {
    '$addFields': {
      'singleCoordinate': {
        '$function': {
          'body': 'function(coordinates){return ((coordinates[1] 90)*180 coordinates[0])*1000000000000;}', 
          'args': [
            '$coordinates', '$geonear'
          ], 
          'lang': 'js'
        }
      }
    }
  }, {
    '$group': {
      '_id': {
        '$subtract': [
          '$singleCoordinate', {
            '$mod': [
              '$singleCoordinate', 100
            ]
          }
        ]
      }, 
      'coordinates': {
        '$first': '$coordinates'
      }, 
      'avgType': {
        '$avg': '$type'
      }
    }
  }, {
    '$addFields': {
      'latitude': {
        '$arrayElemAt': [
          '$coordinates', 1
        ]
      }, 
      'longitude': {
        '$arrayElemAt': [
          '$coordinates', 0
        ]
      }, 
      'weight': {
        '$multiply': [
          '$avgType', '$_id'
        ]
      }
    }
  }, {
    '$project': {
      '_id': false, 
      'coordinates': false, 
      'avgType': false
    }
  }
]