MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Generazione di una struttura per l'aggregazione

Quando ho avuto un momento per pensarci, sono tornato a casa su Perl e ho risolto:

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] );

Quindi il processo è stato incredibilmente semplice.

  1. Scorri ogni elemento nell'array e ottieni la chiave e il valore per la voce

  2. Crea un nuovo "documento" che abbia nell'argomento array alla chiave "$cond" solo due delle tre voci richieste. Questi sono i valori assegnati per testare "$user_id" e il valore "weight" restituito.

  3. Verifica la lunghezza della variabile esterna per stack , e se era vuoto (prima volta) allora premere il valore di 0 come si vede nell'ultimo elemento nidificato alla fine della chiave "$cond" nel documento.

  4. Se c'era già qualcosa (lunghezza> 0), prendi quel valore e premi come terzo valore nella chiave "$cond" del documento.

  5. Rimetti quel documento come valore di stack e ripeti per l'elemento successivo

Quindi ci sono alcune cose nell'elenco come l'inversione dell'ordine dell'input, che non è richiesto ma produce un ordine naturale nell'output nidificato. Inoltre, la mia scelta per quello "stack" esterno era un array perché gli operatori di test sembravano semplici. Ma in realtà è solo un valore singolare che continua a essere riutilizzato, aumentato e sostituito.

Anche la stampa JSON è lì solo per mostrare l'output. Tutto ciò che è veramente desiderato è il valore risultante di stack da fondere nella struttura.

Quindi ho convertito la logica in ruby, così come il linguaggio utilizzato dall'OP da cui ho tratto ispirazione su come generare questa struttura nidificata:

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])

E poi alla fine nel modulo finale per generare la pipeline che l'OP voleva:

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 )

Quindi era un modo per generare una struttura da passare in aggregato per applicare "pesi" specifici a un user_id e ordina i risultati nella raccolta.