MongoDB聚合运算符:$zip

发布于:2024-05-16 ⋅ 阅读:(64) ⋅ 点赞:(0)

MongoDB聚合运算符:$zip


$zip用于将输入数组的元素重新组合转换为新的数组,重组转换的的规则是使用输入数组的第一个元素重组为第一个数组,使用第二个元素重组为第二个数组,以此类推。

例如,[ [ 1, 2, 3 ], [ "a", "b", "c" ] ]转换后为[ [ 1, "a" ], [ 2, "b" ], [ 3, "c" ] ]

语法

{
    $zip: {
        inputs: [ <array expression1>,  ... ],
        useLongestLength: <boolean>,
        defaults:  <array expression>
    }
}
  • inputs:表达式数组,数组的每个表达式可解析为数组。这些输入数组的元素组合成输出数组。
    如果任何一个输入数组的解析值为空或指向一个缺失字段,$zip将返回空值。
    如果输入数组中的任何一个没有解析为数组或空值,或者指向一个缺失字段,$zip将返回错误信息。
  • useLongestLength:布尔值,用于指定最长数组的长度是否决定输出数组中数组的个数。
    默认值为 false,最短数组的长度决定输出数组中数组的个数。
  • 如果输入数组的长度不同,则使用默认元素值数组。必须同时指定 useLongestLength: true,否则$zip将返回错误。
    如果useLongestLength: true,但defaults为空或未指定,$zip将使用null作为默认值。
    如果指定了非空defaults,则必须为每个输入数组指定默认值,否则$zip返回错误。

使用

输入数组的长度不要求相同。默认情况下,输出数组的长度为最短输入数组的长度,但useLongestLength选项可以指定$zip输出与最长输入数组的长度是否一致。

参考下面的例子来说明:

例1:

{ $zip: { inputs: [ [ "a" ], [ "b" ], [ "c" ] ] }}

结果:

[ [ "a", "b", "c" ] ]

例2:

{ $zip: { inputs: [ [ "a" ], [ "b", "c" ] ] } }

结果:

[ [ "a", "b" ] ]

例3:

{
  $zip: {
     inputs: [ [ 1 ], [ 2, 3 ] ],
     useLongestLength: true
  }
}

结果:

[ [ 1, 2 ], [ null, 3 ] ]

例4:

{
  $zip: {
     inputs: [ [ 1 ], [ 2, 3 ], [ 4 ] ],
     useLongestLength: true,
     defaults: [ "a", "b", "c" ]
  }
}

结果:

因为useLongestLength: true$zip会用缺省值元素填充较短的输入数组。

[ [ 1, 2, 4 ], [ "a", 3, "c" ] ]

举例

矩阵转置

使用下面的脚本创建matrices集合:

db.matrices.insertMany([
  { matrix: [[1, 2], [2, 3], [3, 4]] },
  { matrix: [[8, 7], [7, 6], [5, 4]] },
])

要计算这个集合中每个 3x2 矩阵的转置,可以使用下面的聚合运算:。

db.matrices.aggregate([{
  $project: {
    _id: false,
    transposed: {
      $zip: {
        inputs: [
          { $arrayElemAt: [ "$matrix", 0 ] },
          { $arrayElemAt: [ "$matrix", 1 ] },
          { $arrayElemAt: [ "$matrix", 2 ] },
        ]
      }
    }
  }
}])

执行的结果为:

{ "transposed" : [ [ 1, 2, 3 ], [ 2, 3, 4 ] ] }
{ "transposed" : [ [ 8, 7, 5 ], [ 7, 6, 4 ] ] }

过滤并保留索引

可以使用$zip$filter来获取数组中的元素子集,同时保存每个元素的原始索引。

使用脚本创建pages集合:

db.pages.insertOne( {
  "category": "unix",
  "pages": [
    { "title": "awk for beginners", reviews: 5 },
    { "title": "sed for newbies", reviews: 0 },
    { "title": "grep made simple", reviews: 2 },
] } )

下面的聚合首先把pages数组中的元素连同其索引一起压缩,然后只筛选出至少有一条评论的页面::

db.pages.aggregate([{
  $project: {
    _id: false,
    pages: {
      $filter: {
        input: {
          $zip: {
            inputs: [ "$pages", { $range: [0, { $size: "$pages" }] } ]
          }
        },
        as: "pageWithIndex",
        cond: {
          $let: {
            vars: {
              page: { $arrayElemAt: [ "$$pageWithIndex", 0 ] }
            },
            in: { $gte: [ "$$page.reviews", 1 ] }
          }
        }
      }
    }
  }
}])

结果为:

{
  "pages" : [
    [ { "title" : "awk for beginners", "reviews" : 5 }, 0 ],
    [ { "title" : "grep made simple", "reviews" : 2 }, 2 ] ]
}