首页 > 解决方案 > 如何将字段(具有 KV 对的对象数组)转换为仅具有值的数组数组?

问题描述

我在 MongoDB 中有一个集合,其中有一个名为“geometry”的字段,其纬度和经度如下:

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

我想将字段几何转换成这样的东西,以符合 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
                ]
            ]                
        }

我已经尝试过使用它并逐条修改数据记录,但结果并不一致。而且,我试图避免遍历每条记录并一一改变结构。有没有办法有效地做到这一点?

标签: arraysmongodbaggregation-frameworkpymongogeojson

解决方案


您会认为以下代码理论上应该可以工作:

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
})

但是,根据SERVER-37635,MongoDB 在此阶段的工作方式是上述查询会导致令人惊讶的输出,其中该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 票证的评论部分,Charlie Swanson 提到了另一种解决方法,它$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"
        }
      }
    }
  }
])

推荐阅读