当我有时间思考这个问题时,我跑回家使用 Perl 并解决了这个问题:
use Modern::Perl;
use Moose::Autobox;
use JSON;
my $encoder = JSON->new->pretty;
my $input = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7 }, { 1 => 8 } ];
my $stack = [];
foreach my $item ( reverse @{$input} ) {
while ( my ( $key, $value ) = each %{$item} ) {
my $rec = {
'$cond' => [
{ '$eq' => [ '$user_id', int($key) ] },
$value
]
};
if ( $stack->length == 0 ) {
$rec->{'$cond'}->push( 0 );
} else {
my $last = $stack->pop;
$rec->{'$cond'}->push( $last );
}
$stack->push( $rec );
}
}
say $encoder->encode( $stack->[0] );
所以这个过程非常简单。
遍历数组中的每个项目并获取该条目的键和值
创建一个新的“文档”,其中“$cond”键的数组参数仅包含所需三个条目中的两个。这些是分配给测试“$user_id”的值和返回的“权重”值。
测试外部变量的长度stack,如果它是空的(第一次通过)那么push的价值0
如文档中“$cond”键末尾的最后一个嵌套元素所示。
如果已经有东西存在(长度> 0),则取该值并push它作为文档的“$cond”键中的第三个值。
将该文档作为以下值放回stack并重复下一个项目
因此,列表中有一些内容,例如反转输入的顺序,这不是必需的,但会在嵌套输出中产生自然顺序。另外,我对外部“堆栈”的选择是一个数组,因为测试运算符看起来很简单。但它实际上只是一个不断被重用、增强和替换的奇异值。
JSON 打印也只是为了显示输出。真正想要的是结果值stack合并到结构中。
然后我将逻辑转换为 ruby,就像 OP 使用的语言一样,我从那里获得了如何生成此嵌套结构的灵感:
require 'json'
input = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7 }, { 1 => 8 } ]
stack = []
input.reverse_each {|item|
item.each {|key,value|
rec = {
'$cond' => [
{ '$eq' => [ '$user_id', key ] },
value
]
}
if ( stack.length == 0 )
rec['$cond'].push( 0 )
else
last = stack.pop
rec['$cond'].push( last )
end
stack.push( rec )
}
}
puts JSON.pretty_generate(stack[0])
然后最终进入最终形式以生成OP想要的管道:
require 'json'
userWeights = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7}, { 1 => 8 } ]
stack = []
userWeights.reverse_each {|item|
item.each {|key,value|
rec = {
'$cond' => [
{ '$eq' => [ '$user_id', key ] },
value
]
}
if ( stack.length == 0 )
rec['$cond'].push( 0 )
else
last = stack.pop
rec['$cond'].push( last )
end
stack.push( rec )
}
}
pipeline = [
{ '$project' => {
'user_id' => 1,
'content' => 1,
'date' => 1,
'weight' => stack[0]
}},
{ '$sort' => { 'weight' => -1, 'date' => -1 } }
]
puts JSON.pretty_generate( pipeline )
因此,这是一种生成要传递到聚合的结构的方法,以便应用特定于某个对象的“权重”user_id
并对集合中的结果进行排序。