Mongodb-聚合函数嵌套ob

时间:2019-10-01 05:10:58

标签: mongodb geospatial

我们需要计算地理空间数据的最小边界矩形(MBR)。 在oracle中,我们具有SDO_AGGR_MBR函数,MongoDB中是否有任何类似的函数。

"coord" : {
    "type" : "Polygon",
    "coordinates" : [ 
        [ 
            [ 
                25.5377574375611, 
                42.8545750237221
            ], 
            [ 
                47.7803203666229, 
                42.8545750237221
            ], 
            [ 
                47.7803203661319, 
                52.0987759993153
            ], 
            [ 
                25.5377574370701, 
                52.0987759993153
            ], 
            [ 
                25.5377574375611, 
                42.8545750237221
            ]
        ]
    ]
}

我们具有如上所述的几何数据,但是坐标长度可能会有所不同。因此,我们需要从这些数据中找到minxminymaxxmaxy

2 个答案:

答案 0 :(得分:1)

我认为没有内置函数。但您只需执行以下操作;

db.collection.aggregate([
  {
    $unwind: "$coordinates"
  },
  {
    $unwind: "$coordinates"
  },
  {
    $group: {
      _id: null,
      minX: {
        $min: { $arrayElemAt: [ "$coordinates", 0 ] }
      },
      maxX: {
        $max: { $arrayElemAt: [ "$coordinates", 0 ] }
      },
      minY: {
        $min: { $arrayElemAt: [ "$coordinates", 1 ] }
      },
      maxY: {
        $max: { $arrayElemAt: [ "$coordinates", 1 ] }
      }
    }
  }
])

首先用$unwind解开coordinates数组的位置(两次额外的[ ]块),以便aggregate pipeline可以对其进行迭代。然后,我们仅将$groupa special operation一起使用mongoplayground来计算数组所有元素的最小/最大值。

这将使您收到请求的答复;

_id: null

检查https://medium.com/@felixblaschke/fancy-background-animations-in-flutter-4163d50f5c37

答案 1 :(得分:1)

最有效的方法是将$map$reduce运算符与$let一起使用。这使您可以通过处理数组的 inline 来处理每个文档,然后使用$min$max运算符来获取边界值:

db.collection.aggregate([
  { "$replaceRoot": {  
    "newRoot": {
      "$let": {
        "vars": {
          "m": {
            "$map": {
              "input": {
                "$reduce": {
                  "input": "$coord.coordinates",
                  "initialValue": [],
                  "in": {
                    "$concatArrays": [ "$$value", "$$this"]
                  }
                }
              },
              "in": {
                "x": { "$arrayElemAt": [ "$$this", 0 ] },
                "y": { "$arrayElemAt": [ "$$this", 1 ] }
              }
            }
          }
        },
        "in": {
          "_id": "$_id",
          "coord": "$coord",
          "minX": { "$min": "$$m.x" },
          "minY": { "$min": "$$m.y" },
          "maxX": { "$max": "$$m.x" },
          "maxY": { "$max": "$$m.y" }
        }
      }
    }
  }}
])

输出将是:

{
        "_id" : ObjectId("5d9330e95994eb7018f59218"),
        "coord" : {
                "type" : "Polygon",
                "coordinates" : [
                        [
                                [
                                        25.5377574375611,
                                        42.8545750237221
                                ],
                                [
                                        47.7803203666229,
                                        42.8545750237221
                                ],
                                [
                                        47.7803203661319,
                                        52.0987759993153
                                ],
                                [
                                        25.5377574370701,
                                        52.0987759993153
                                ],
                                [
                                        25.5377574375611,
                                        42.8545750237221
                                ]
                        ]
                ]
        },
        "minX" : 25.5377574370701,
        "minY" : 42.8545750237221,
        "maxX" : 47.7803203666229,
        "maxY" : 52.0987759993153
}

请注意$replaceRoot聚合管道阶段的用法,因为这将允许带有$let的嵌套表达式向文档提供全局变量,从而可以用于任何输出属性。

这里的$reduce主要用于将标准GeoJSON形式的数组扁平化成一个坐标对数组,而没有附加的边界数组。

然后,将输入馈送到使用$map$arrayElemAt,以便将每个坐标对重新映射到具有{{ 1}}和x键。对于$let的实际执行或 output 部分,这使事情变得更加简单。

  

注意:针对$arrayElemAt中的每个键使用$map的另一种方法很可能是使用$zip$arrayToObject:< / p>

y
     

它在整体输出中具有相同的原理,但是利用$zip产生“成对”数组的优势,这对$arrayToObject来说也是有效的输入,以产生最终的 object < / em>表单。

在最后一部分中,我们现在基本上有了一个对象数组,它们具有命名键 "in": { "$arrayToObject": { "$zip": { "inputs": [ ["x","y"], "$$this" ] } } } x。 MongoDB提供了一种方便的方法来 remap ,简单地将名称命名为y的那些命名键的值(其中"$$m.x"表达式与$let的命名变量和是我们的对象数组,而"$$m部分当然意味着 .x 的值。这本身就是$map语句的基本简写,适合这种特殊用法。

这些特定属性值的数组现在可以应用于$min$max运算符,这就是获取xmin坐标的方式。边界矩形。


请注意,数组的内联运算符始终应优先于$unwind

$unwind聚合流水线阶段是一种将数组元素基本上展平到单独文档中的古老介绍性方法。

当您实际上想对值作为数组中的键进行分组时,这是必需的,但是实际上不需要的大多数操作(如此操作)可以用更多的操作来完成现代方法。

$unwind的使用实际上是一个巨大的性能损失,因为它的功能是将包含数组的字段的整个父文档内容复制到自己的新文档中。特别是在大型数据集中,由于I / O和内存使用量大大增加,这对性能产生了非常不利的影响。

主要的经验教训是,除非必须执行该操作(此处不是),否则您不应在聚合管道中使用$unwind。它看起来 可能更容易理解,但是您的代码实际上通过包含它而正在损害正在运行的系统。


替代客户方法

还请注意,如果您实际上不需要任何进一步的汇总处理所需的结果,那么在处理每个文档时在客户端进行编码可能会更干净。

例如,这是外壳的普通JavaScript版本:

max

具有完全相同的输出,并且几乎不像聚合管道所需的BSON运算符那样笨拙。