Как преобразовать поле, представляющее собой массив объектов с парами KV, в массив массивов только с значениями? - PullRequest
0 голосов
/ 15 октября 2018

У меня есть коллекция в MongoDB, в которой есть поле с именем "geometry" с широтой и долготой, например:

{ 
    "abc":"xyz",
    "geometry" : [
        {
            "lat" : 45.0, 
            "lng" : 25.0
        }, 
        {
            "lat" : 46.0, 
            "lng" : 26.0
        }
    ]
}

Я хочу преобразовать поле geometry примерно так, чтобы соответствовать формату GeoJSON:

{
            "abc":"xyz",
            "geometry": {
            "type": "LineString",
                "coordinates": [
                    [
                        25.0,
                        45.0
                    ],
                    [
                        26.0,
                        46.0
                    ]
                ]                
            }
}

Операция, в основном, заключается в том, чтобы взять массив объектов с двумя парами K / V, выбрать только значения и сохранить их как массивмассивы (с обратным порядком, поэтому значение «lng» стоит первым).

Мои неудачные попытки: Я пытался использовать агрегат и пытался спроецировать следующее:

"geometry": {"type":"LineString", "coordinates":["$points.lng","$points.lat"] }

, который дал мне результат, подобный следующему:

"geometry": {
        "type": "LineString",
            "coordinates": [
                [
                    25.0,
                    26.0
                ],
                [
                    45.0,
                    46.0
                ]
            ]                
        }

Я пытался работать с этим и изменять запись данных по записи, но результаты не согласованы.И я стараюсь не проходить каждую запись и не менять структуру по очереди.Есть ли способ сделать это эффективно?

1 Ответ

0 голосов
/ 15 октября 2018

Можно подумать, что следующий код должен теоретически работать:

db.collection.aggregate({
    $project: {
        "abc": 1, // include the "abc" field in the output
        "geometry": { // add a new geometry sub-document
            "type": "LineString", // with the hardcoded "type" field
            "coordinates": {
                $map: {
                    "input": "$geometry", // transform each item in the "geometry" array
                    "as": "this",
                    "in": [ "$$this.lng", "$$this.lat" ] // into an array of values only, ith "lng" first, "lat" second
                }
            }
        }
    }
}, {
    $out: "result" // creates a new collection called "result" with the transformed documents in it
})

Однако , как MongoDB работает на данном этапе в соответствии с SERVER-37635 заключается в том, что приведенный выше запрос приводит к неожиданному выводу, когда поле coordinates содержит требуемый результат несколько раз.Таким образом, следующий запрос можно использовать для генерации желаемого результата:

db.collection.aggregate({
    $addFields: {
        "abc": 1,
        "geometry2": {
            "type": "LineString",
            "coordinates": {
                $map: {
                    "input": "$geometry",
                    "as": "this",
                    "in": [ "$$this.lng", "$$this.lat" ]
                }
            }
        }
    }
}, {
    $project: {
        "abc": 1,
        "geometry": "$geometry2"
    }
}, {
    $out: "result"
})

В разделе комментариев билета JIRA, упомянутого выше, Чарли Свансон упоминает другой обходной путь, который использует $let, чтобы «обмануть» MongoDB винтерпретировать запрос желаемым образом.Я пересылаю его сюда (обратите внимание, что в нем отсутствует часть $out):

db.collection.aggregate([
  {
    $project: {
      "abc": 1,
      "geometry": {
        $let: {
          vars: {
            ret: {
              "type": "LineString",
              "coordinates": {
                $map: {
                  "input": "$geometry",
                  "as": "this",
                  "in": [
                    "$$this.lng",
                    "$$this.lat"
                  ]
                }
              }
            }
          },
          in: "$$ret"
        }
      }
    }
  }
])
...