Mongodb 如何使用聚合框架创建新的数组字段

Mongodb 如何使用聚合框架创建新的数组字段,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我开始使用mongoDb,我只需要一个简单的用例 假设我有一个集合“aCollection”,其中包含如下条目: { _id:ObjectId(123), 拉脱维亚:4856623, 长:256332 } 我想创建一个新集合,其中包含以下条目: { _id:ObjectId(123), 拉脱维亚:4856623, 长:256332, 几何体:{ 键入:“点”, 座标:[4856623256332] } } 我想到了聚合框架: db.aCollection.aggregate([{$proje

我开始使用mongoDb,我只需要一个简单的用例

假设我有一个集合“aCollection”,其中包含如下条目:

{
_id:ObjectId(123),
拉脱维亚:4856623,
长:256332
}
我想创建一个新集合,其中包含以下条目:

{
_id:ObjectId(123),
拉脱维亚:4856623,
长:256332,
几何体:{
键入:“点”,
座标:[4856623256332]
}
}
我想到了聚合框架:

db.aCollection.aggregate([{$project:{
_id:1,
拉丁语:1,
龙:1,,
几何体:{
类型:{$concat:[“点”]},
坐标:[“$lat”,“$long”]
}
}}])
但它不起作用,我有一个例外:

“异常:对象表达式中不允许的字段类型数组(在“坐标”处)”

以下聚合正在工作,但未产生预期结果:

db.aCollection.aggregate([{$project:{
_id:1,
拉丁语:1,
龙:1,,
几何体:{
类型:{$concat:[“点”]},
坐标:“$lat”
}
}}])
您将如何继续创建此集合 1) 使用聚合框架 2) 没有聚合框架


谢谢

您不需要聚合功能。
find
forEach
insert
是一种潜在的方法:

db.aCollection.find().forEach( function(myDoc) {
  myDoc.geometry = {type: "Point", coordinates: [myDoc.lat, myDoc.long]};
  db.newCollection.insert(myDoc);
});

它为每个文档调用一个单独的insert,但是如果您有一个小的集合,那么它会很快和脏。

好的,首先让我们了解聚合框架的作用。它只查询可用数据并返回结果。它不会修改原始文档!这就是您编写的第二段代码执行聚合、进行投影并显示成功运行聚合查询的某些结果的原因

要进行您正试图进行的更改,您可以尝试Martin Konecny的回答中的“快速和肮脏”方法,或者您可以修改上载数据的代码并执行新的上载


既然我看到在lat/long值中使用逗号而不是小数点,我想说的是,如果稍后您将尝试查询此地理空间数据,您最好再次正确地上传它。

在现代MongoDB版本中,最有效的方法是使用现有文档属性简单地为数组标记。MongoDB 3.2中引入了数组的直接表示法:

db.collection.aggregate([
  { "$project": {
    "lat": 1,
    "long": 1,
    "geometry": {
      "type": { "$literal": "Point" },
      "coordinates": [ "$lat", "$long" ]
    }
  }},
  { "$out": "newcollection" }
])
或者甚至使用简单地将新属性“附加”到文档中:

db.collection.aggregate([
  { "$addFields": {
    "geometry": {
      "type": { "$literal": "Point" },
      "coordinates": [ "$lat", "$long" ]
    }
  }},
  { "$out": "newcollection" }
])

如果您使用的是MongoDB 2.6及更高版本,那么您可以通过聚合框架实现这一点,并避免在客户端程序中循环结果以创建新集合

这里帮助您的主要功能是将输出发送到新集合的操作符。但是,为了创建所需的阵列,还需要稍微聪明一点

db.collection.aggregate([
{“$project”:{
“lat”:1,
"长":一,,
“type”:{“$literal”:[“lat”,“long”]}
}},
{“$unwind”:“$type”},
{“$组”:{
“\u id”:“$\u id”,
“lat”:{“$first”:“$lat”},
“long”:{“$first”:“$long”},
“坐标”:{
“$push”:{
“$cond”:[
{“$eq”:[“$type”,“lat”]},
“$lat”,
“$long”
]
}
}
}},
{“$project”:{
“lat”:1,
"长":一,,
“几何学”:{
“类型”:{“$literal”:“点”},
“坐标”:“$coordinates”
}
}},
{“$out”:“newcollection”}
])
因此,它利用操作符在管道的前端指定一个新数组。该操作员将在文档属性中准确地放置内容其提供方式。因此不允许变量替换,因此为“文字”

为了创建“coordintes”数组,我们只需解开第一个数组,它基本上会创建两个在“type”中具有不同值的文档。然后在stage中使用它有条件地将“$lat”或“$long”值添加到该数组中

最后再次使用完成文档结构,然后将所有输出发送到新集合


请注意,只有当您打算创建一个新集合并避免“通过线路”发送流量时,这才有意义。这不能纯粹在聚合框架中用于重新塑造文档,以便在聚合管道中执行“地理空间”查询,因为“地理空间”查询只有在对集合进行实际索引时才起作用


因此,这可能有助于您根据需要创建新集合,但至少它是如何使用聚合框架从不同值创建数组的示例(实际上是两个示例)

看起来MongoDB 3.2提供了使用聚合框架创建GeoJSON点的相当简单和优雅的方法

我们每天必须对大约200万条记录执行两次转换,因此聚合框架是最快、可能也是最可靠的方法

下面是一个Mongoose示例,介绍了如何将地理位置数据从具有经度/纬度的集合转换为具有GeoJSON点的集合

Locations
    .aggregate([
        {
            $project : {
                _id: 0,
                "location": {
                    "type": { $literal: "Point" }, 
                    "coordinates": ["$longitude", "$latitude"]
                }
            }
        },
        {
            $out : 'test_1'
        }])
    .exec(function(err,data) {
        if (err) {
            console.error(err);
        } else {
            console.log("Done transforming.");
        }
    });

非常感谢。到目前为止非常有用:)如果人们担心为不存在的字段创建“null”值,我们可以始终使用“$filter”将其过滤掉。