use*_*368 8 mongodb mongodb-query aggregation-framework
我开始使用mongoDb而且我遇到了一个简单的用例.
假设我有一个集合'aCollection',其条目如下:
{
_id: ObjectId(123),
lat: 48,56623,
long: 2,56332
}
Run Code Online (Sandbox Code Playgroud)
我想用这样的条目创建一个新的集合:
{
_id: ObjectId(123),
lat: 48,56623,
long: 2,56332,
geometry : {
type: "Point",
coordinates: [48,56623, 2,56332]
}
}
Run Code Online (Sandbox Code Playgroud)
我想到了聚合框架:
db.aCollection.aggregate([{$project: {
_id: 1,
lat: 1,
long: 1,
geometry: {
type: {$concat: ["Point"]},
coordinates: ["$lat", "$long"]
}
}}])
Run Code Online (Sandbox Code Playgroud)
但它不起作用,我得到这个例外:
"异常:对象表达式中不允许的字段类型数组(位于'坐标')"
以下聚合正在起作用,但它不会产生预期的结果:
db.aCollection.aggregate([{$project: {
_id: 1,
lat: 1,
long: 1,
geometry: {
type: {$concat: ["Point"]},
coordinates: "$lat"
}
}}])
Run Code Online (Sandbox Code Playgroud)
如何在没有聚合框架的情况下使用聚合框架2)继续创建此集合1)
谢谢
Nei*_*unn 10
在Modern MongoDB版本中,最有效的方法是使用现有文档属性简单地表示数组.MongoDB 3.2中引入了数组的直接表示法:
db.collection.aggregate([
{ "$project": {
"lat": 1,
"long": 1,
"geometry": {
"type": { "$literal": "Point" },
"coordinates": [ "$lat", "$long" ]
}
}},
{ "$out": "newcollection" }
])
Run Code Online (Sandbox Code Playgroud)
甚至$addFields用于简单地将新属性"追加"到文档中:
db.collection.aggregate([
{ "$addFields": {
"geometry": {
"type": { "$literal": "Point" },
"coordinates": [ "$lat", "$long" ]
}
}},
{ "$out": "newcollection" }
])
Run Code Online (Sandbox Code Playgroud)
如果您使用的是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" }
])
Run Code Online (Sandbox Code Playgroud)
因此,这使用了$literal运算符,以便在管道的头部指定一个新数组.此运算符将在文档属性中准确提供内容.因此,不允许任何变量替换,因此是"文字".
为了创建"coordintes"数组,我们简单地展开第一个数组,它基本上创建了两个在"type"中具有不同值的文档.然后在$group阶段中使用它来有条件地$push将"$ lat"或"$ long"值放到该数组上.
最后$project再次使用来完成文档结构,然后$out将所有输出发送到新集合.
请注意,这只有在您打算创建新集合并避免"通过网络"发送流量时才有意义.这不能仅仅在聚合框架内用于重新整形文档,以便在相同的聚合管道中执行"地理空间"查询,因为"地理空间"查询仅在实际对集合编制索引时才有效.
因此,这可以帮助您根据需要创建新集合,但至少它可以作为如何使用聚合框架从不同值创建数组的示例(或实际上两个示例).
为此,您不需要聚合功能。A find、forEach、 和insert是一种可能的方法:
db.aCollection.find().forEach( function(myDoc) {
myDoc.geometry = {type: "Point", coordinates: [myDoc.lat, myDoc.long]};
db.newCollection.insert(myDoc);
});
Run Code Online (Sandbox Code Playgroud)
它为每个文档调用单独的插入,但如果您的集合较小,则速度快且脏。