如何使用聚合框架创建新的数组字段 [英] How create a new array field with the aggregate framework

查看:91
本文介绍了如何使用聚合框架创建新的数组字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始使用mongoDb,并且坚持使用一个简单的用例.

I'm starting to use mongoDb and I'm stuck with a simple use case.

假设我有一个集合"aCollection",其条目如下:

Let's say I've got a collection 'aCollection' with entries such as this:

{ 
    _id: ObjectId(123),
    lat: 48,56623,
    long: 2,56332
}

并且我想使用以下条目创建一个新集合:

and I want to create a new collection with entries like this:

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

但是它不起作用,我得到了这个异常:

But it ain't working and I get this exception:

例外:对象表达式中的字段类型为数组(在坐标"处)"

"exception: disallowed field type Array in object expression (at 'coordinates')"

以下聚合有效,但未产生预期结果:

The following aggregation is working but it doesn't produce the expected result:

db.aCollection.aggregate([{$project: { 
    _id: 1,
    lat: 1,
    long: 1,
    geometry: { 
        type: {$concat: ["Point"]},
        coordinates: "$lat"
    }
}}])

您将如何继续创建此收藏集 1)用聚合框架 2)没有聚合框架

How would you proceed to create this collection 1) with the aggregation framework 2) without the aggregation framework

谢谢

推荐答案

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

In Modern MongoDB releases the most efficient way is to simply notate the array using the existing document properties. Direct notation of arrays was introduced in MongoDB 3.2:

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

或者甚至使用 $addFields 来简单地附加文档的新属性:

Or even using $addFields to simply "append" the new property to the documents:

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


如果您使用的是MongoDB 2.6及更高版本,则可以使用聚合框架来执行此操作,并避免在客户端程序中循环结果以创建新集合.


If you are using MongoDB 2.6 and above you can do this with the aggregation framework and avoid looping results in your client program in order to create a new collection.

这里为您提供帮助的主要功能是 运算符,用于将输出发送到新集合.但是,为了创建所需的数组也要聪明一点.

The main feature here that help you are the $out operator for sending the output to a new collection. But also being a little clever in order to create the array that you need.

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 运算符,以便在管道的开头指定一个新数组.此操作员将完全将内容放置在文档属性中.因此,不允许使用任何变量替换,因此是文字".

So this makes use of the $literal operator in order to specify a new array at the head of the pipeline. This operator will put content in the document property exactly how it is supplied. So no variable substitutions are allowed, hence "literal".

为了创建"coordintes"数组,我们简单地展开第一个数组,该数组实际上创建了每个文档中的两个,在"type"中具有不同的值.然后在 $group 阶段有条件地 $push 将"$ lat"或"$ long"值添加到该数组上.

In order to create the "coordintes" array, we simply unwind that first array which essentially creates two of every document with a different value in "type". This is then used in the $group stage to conditionally $push either the "$lat" or "$long" value onto that array.

最后使用 $project 再次确定文档结构,然后 $out 将所有输出发送到新集合.

Finally use $project again to finalize the document structure and then $out sends all output to the new collection.

请注意,这仅在您打算创建新集合并避免在线"发送流量的情况下才有意义.不能仅在聚合框架内使用它来重塑文档的形状,然后在与地理空间"查询相同的聚合管道中执行地理空间"查询,仅当在集合上实际建立索引时才可以使用

Note that this only makes sense if your intention is to create a new collection and avoid sending traffic "over the wire". This could not be used purely within the aggregation framework to re-shape your document with the intent to then do a "geo-spatial" query in that same aggregation pipeline as "geo-spatial" queries will only work when actually indexed on a collection.

因此,这可能会帮助您根据需要创建一个新的集合,但至少它充当了如何使用聚合框架从不同值创建数组的示例(或两个示例).

So this may help you create a new collection as you want to, but at least it serves as example ( or two examples actually ) of how to create an array's out of different values with the aggregation framework.

这篇关于如何使用聚合框架创建新的数组字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆