sql >> Databáze >  >> NoSQL >> MongoDB

Generování struktury pro agregaci

Když jsem měl chvilku na přemýšlení, běžel jsem domů do perlu a vyřešil to:

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

Proces byl tedy oslnivě jednoduchý.

  1. Projděte každou položku v poli a získejte klíč a hodnotu položky

  2. Vytvořte nový „dokument“, který má v argumentu pole ke klíči „$cond“ pouze dvě ze tří požadovaných položek. Toto jsou hodnoty přiřazené k testování "$user_id" a vrácené hodnoty "weight".

  3. Otestujte délku vnější proměnné na zásobník a pokud byla prázdná (první průchod), zatlačte hodnotu 0 jak je vidět v posledním vnořeném prvku na konec klíče "$cond" v dokumentu.

  4. Pokud tam již něco bylo (délka> 0), vezměte tuto hodnotu a zatlačte to jako třetí hodnota v klíči "$cond" pro dokument.

  5. Vložte tento dokument zpět jako hodnotu zásobník a opakujte pro další položku

Takže ve výpisu je několik věcí, jako je obrácení pořadí vstupu, což není povinné, ale vytváří přirozené pořadí ve vnořeném výstupu. Také moje volba pro tento vnější "stack" byla pole, protože testovací operátoři se zdáli být jednoduché. Ale ve skutečnosti je to jen ojedinělá hodnota, která se neustále znovu používá, rozšiřuje a nahrazuje.

Také tisk JSON je zde pouze pro zobrazení výstupu. Vše, co se skutečně chce, je výsledná hodnota stack být začleněn do struktury.

Poté jsem převedl logiku na ruby, stejně jako jazyk používaný OP, odkud jsem získal inspiraci pro vytvoření této vnořené struktury:

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

A pak nakonec do konečné podoby, aby se vygeneroval kanál, který OP chtěl:

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 )

Takže to byl způsob, jak vygenerovat strukturu, která bude předána do agregace, aby bylo možné použít „váhy“, které jsou specifické pro user_id a seřadit výsledky ve sbírce.



  1. Zřetězte řetězcové hodnoty v poli do jednoho pole v MongoDB

  2. MongoDB $setDifference

  3. Uvnitř nové podpory Apache HBase pro MOB

  4. Atomicita, izolace a souběžnost v MongoDB