【问题标题】:Mongo Aggregation select and push last element in arrayMongodb聚合选择并推送数组中的最后一个元素
【发布时间】:2014-06-22 11:19:55
【问题描述】:

我有以下结构的文档:

{
...,
trials:[ {...,
          ref:[{a:1,b:2},{a:2,b:2},...]
         },
         {...,
          ref:[{a:1,b:2}]
         },
         ...,
       ]
}

ref 是一个保证长度至少为 1 的数组。

如果我想计算每个 ref 数组中每个元素的单独出现次数,我将使用以下聚合。 (这很好用)

db.cl.aggregate([
   {$unwind:"$trials"},
   {$unwind:"$trials.ref"},
   {$group:{_id:"$trials.ref", count:{$sum:1}}}
])

现在我想做同样的事情,但只使用每个 ref 数组中的最后一个元素。我需要一种只选择聚合管道中每个数组的最后一个元素的方法。

我首先认为我可以添加一个中间步骤,通过执行以下操作来获取我想要分组的所有元素:

db.cl.aggregate([
   {$unwind:"$trials"},
   {$group:{_id:null,arr:{$push:"$trials.ref.-1"}}},...
])

我也尝试使用带有$match 的位置运算符。

db.cl.aggregate([
    {$unwind:"$trials"},
    {$match:{"trials.ref.$":-1}},...
])

或者尝试投影最后一个元素。

db.cl.aggregate([
    {$unwind:"$trials"},
    {$project:{ref:"$trials.ref.1"}}
])

这些都不能让我去任何地方。 $pop 运算符在聚合管道中无效。 $last 运算符在这里并不是很有用。

关于如何只使用ref 数组的最后一个元素有什么想法吗?我宁愿继续使用聚合框架,而不是使用 Map Reduce。

【问题讨论】:

  • 比您想象的要棘手得多。见here
  • 我完全意识到这是一个有趣的问题。我在这里只展示了我的一些尝试。我花了很长时间思考这个问题。我可以查询所有ref 数组并在本地进行计算,但我宁愿不这样做。
  • 我引用了另一个问题,因为您面临的问题是“top-n”问题。你不能在聚合框架中$slice。鉴于您想要做的事情,这是一个问题。您可以使用$first$match 层来模拟它,如图所示。但是没有简单的方法来获得每个分组数组的“n”个结果。这基本上就是你要问的。

标签: mongodb mapreduce aggregation-framework


【解决方案1】:

聚合框架确实没有办法处理这个问题。除了缺少任何“切片”类型运算符之外,这里真正的问题是缺少任何标记来告诉您的内部数组在哪里结束,并且对于任何其他形式的文档重新整形确实没有任何方法可以做到这一点。

至少现在,mapReduce 方法非常简单,甚至不需要 reducer:

db.cl.mapReduce(
    function() {
        this.trials.forEach(function(trial) {
            trial.ref = trial.ref.slice(-1);
        });

        var id = this._id;
        delete this._id;

        emit( id, this );
    },
    function(){},
    { "out": { "inline": 1 } }
)

未来可能会有一些希望。某种形式的$slice已经追捧了一段时间。但我确实注意到$mapoperator code 中的这个有趣的sn-p。在这里也列出来:

    output.reserve(input.size());
    for (size_t i=0; i < input.size(); i++) {
        vars->setValue(_varId, input[i]);

        Value toInsert = _each->evaluateInternal(vars);
        if (toInsert.missing())
            toInsert = Value(BSONNULL); // can't insert missing values into array

        output.push_back(toInsert);
    }

注意for 循环和索引值。我会投票将其作为$map 运算符中的变量公开,因为您知道数组的当前位置和长度,您可以有效地进行“切片”。

但是现在,没有办法使用$map 来判断您在数组中的位置,如果您使用$unwind 两个数组,您就会失去内部数组的端点。所以聚合框架目前缺乏解决方案。

【讨论】:

  • 我最终在应用程序端执行此操作。我只是从每个试验中检索完整的数组。
猜你喜欢
  • 2018-05-06
  • 1970-01-01
  • 2021-02-14
  • 2021-10-30
  • 2021-12-17
  • 2022-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多