Когато имах момент да помисля за това, изтичах вкъщи да 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“ и върнатата стойност на „тегло“.
-
Тествайте дължината на външната променлива за стека , и ако е било празно (за първи път), тогава натиснете стойността на
0
както се вижда в последния вложен елемент до края на ключа "$cond" в документа. -
Ако вече е имало нещо (дължина> 0), вземете тази стойност и натиснете го като трета стойност в ключа "$cond" за документа.
-
Поставете този документ обратно като стойност на стека и повторете за следващия елемент
Така че има няколко неща в списъка, като например обръщане на реда на входа, което не е задължително, но създава естествен ред във вложения изход. Освен това моят избор за този външен "стек" беше масив, защото тестовите оператори изглеждаха прости. Но това наистина е просто уникална стойност, която непрекъснато се използва, увеличава и заменя.
Също така 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])
И след това в крайна сметка в окончателната форма, за да генерира тръбопровода, който ОП искаше:
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
и сортирайте резултатите в колекцията.