Mongo Aggregation选择并推入数组中的最后一个元素



我有以下结构的文档:

{
...,
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。

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

至少现在,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 已经被追捧了一段时间。但是我注意到在 $map 操作符代码中有一个有趣的代码片段。只是在这里列出:

    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 你的两个数组,你失去了内部数组的端点。因此,聚合框架在目前的解决方案中是缺乏的。

相关内容

  • 没有找到相关文章

最新更新