如何将一个由K-V对组成的对象数组字段转换为只包含值的二维数组?

3

我在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
                    ]
                ]                
            }
}

这个操作基本上涉及到获取一个包含两个键值对的对象数组,然后仅选择值并将它们存储为数组的数组(顺序相反 - 因此“lng”的值首先出现)。 我的失败尝试: 我尝试使用聚合并尝试投影以下内容:
"geometry": {"type":"LineString", "coordinates":["$points.lng","$points.lat"] }

这给我带来了类似的结果:

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

我曾尝试逐条修改数据记录,但结果不一致。同时,我想避免逐条更改每个记录的结构。有没有一种高效的方法可以解决这个问题?

1个回答

2
你可能认为以下代码在理论上应该是可行的:

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

1
https://mongoplayground.net/p/wdMj4ZQAHhc 不符合预期输出吗? - Ashh
1
@AnthonyWinzlet:我会说这是完美的匹配吗?不,好吧,它不是...发现得很好!但为什么?这似乎是一个MongoDB的bug?! - dnickless
1
是的,因为它不会用 $project 中新的 geometry 字段替换文档中的 geometry 字段。当回答这个问题时,我也感到很惊讶。我也遇到了同样的情况。 - Ashh
@AnthonyWinzlet:哈哈,谢谢。现在我可以去睡觉了,你可以继续工作。;) - dnickless
感谢你们两位提供了我所需要的东西。 - Deepan Anbarasan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接