我开始使用mongoDb而且我遇到了一个简单的用例。
假设我有一个集合'aCollection',其条目如下:
{
_id: ObjectId(123),
lat: 48,56623,
long: 2,56332
}
我想创建一个包含以下条目的新集合:
{
_id: ObjectId(123),
lat: 48,56623,
long: 2,56332,
geometry : {
type: "Point",
coordinates: [48,56623, 2,56332]
}
}
我想到了聚合框架:
db.aCollection.aggregate([{$project: {
_id: 1,
lat: 1,
long: 1,
geometry: {
type: {$concat: ["Point"]},
coordinates: ["$lat", "$long"]
}
}}])
但它没有用,我得到了这个例外:
“exception:对象表达式中不允许的字段类型数组(位于'坐标')”
以下聚合正在运行,但不会产生预期结果:
db.aCollection.aggregate([{$project: {
_id: 1,
lat: 1,
long: 1,
geometry: {
type: {$concat: ["Point"]},
coordinates: "$lat"
}
}}])
您将如何继续创建此集合 1)使用聚合框架 2)没有聚合框架
谢谢
答案 0 :(得分:9)
在Modern MongoDB版本中,最有效的方法是使用现有文档属性简单地标记数组。 MongoDB 3.2中引入了数组的直接表示法:
db.collection.aggregate([
{ "$project": {
"lat": 1,
"long": 1,
"geometry": {
"type": { "$literal": "Point" },
"coordinates": [ "$lat", "$long" ]
}
}},
{ "$out": "newcollection" }
])
甚至使用$addFields
简单地将新属性“追加”到文档中:
db.collection.aggregate([
{ "$addFields": {
"geometry": {
"type": { "$literal": "Point" },
"coordinates": [ "$lat", "$long" ]
}
}},
{ "$out": "newcollection" }
])
如果您使用的是MongoDB 2.6及更高版本,则可以使用聚合框架执行此操作,并避免在客户端程序中循环结果以创建新集合。
此处的主要功能可帮助您将$out
运算符用于将输出发送到新集合。但是为了创建你需要的阵列也有点聪明。
db.collection.aggregate([
{ "$project": {
"lat": 1,
"long": 1,
"type": { "$literal": ["lat","long"] }
}},
{ "$unwind": "$type" },
{ "$group": {
"_id": "$_id",
"lat": { "$first": "$lat" },
"long": { "$first": "$long" },
"coordinates": {
"$push": {
"$cond": [
{ "$eq": [ "$type", "lat" ] },
"$lat",
"$long"
]
}
}
}},
{ "$project": {
"lat": 1,
"long": 1,
"geometry": {
"type": { "$literal": "Point" },
"coordinates": "$coordinates"
}
}},
{ "$out": "newcollection" }
])
因此,这使用$literal
运算符来指定管道头部的新数组。此运算符将内容放入文档属性完全的提供方式。所以不允许任何变量替换,因此是“文字”。
为了创建“coordintes”数组,我们简单地解开第一个数组,它基本上创建了两个在“type”中具有不同值的文档。然后在$group
阶段使用它有条件地$push
该数组上的“$ lat”或“$ long”值。
最后再次使用$project
来完成文档结构,然后$out
将所有输出发送到新集合。
请注意,这只有在您打算创建新集合并避免“通过线路”发送流量时才有意义。这不能仅仅在聚合框架内用于重新整形文档,以便在相同的聚合管道中执行“地理空间”查询,因为“地理空间”查询仅在实际对集合编制索引时才有效
因此,这可以帮助您根据需要创建新集合,但至少它可以作为如何使用聚合框架使用不同值创建数组的示例(或实际上两个示例)。
答案 1 :(得分:1)
您不需要聚合功能。 find
,forEach
和insert
是一种潜在的方法:
db.aCollection.find().forEach( function(myDoc) {
myDoc.geometry = {type: "Point", coordinates: [myDoc.lat, myDoc.long]};
db.newCollection.insert(myDoc);
});
它为每个文档调用一个单独的插入,但如果你有一个小集合,它会很快而且很脏。
答案 2 :(得分:1)
好的,首先让我们了解聚合框架的作用。它仅查询可用数据并返回结果。它不会修改原始文档!这就是为什么你编写的第二段代码执行聚合,进行投影并显示成功运行聚合查询的结果。
要进行您尝试进行的更改,您可以尝试使用Martin Konecny的答案的“快速和脏”方法,也可以修改上传数据和执行全新上传的代码。
因为我看到使用逗号/长值的小数点代替使用小数点,我会说如果以后你会尝试查询这个地理空间数据,你最好再次正确上传它。 / p>
答案 3 :(得分:0)
看起来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.");
}
});