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

Esiste una soluzione alternativa per consentire l'utilizzo di un'espressione regolare nella pipeline di aggregazione di Mongodb

Questa domanda sembra arrivare molte volte senza soluzione. Ci sono due possibili soluzioni che conosco:soluzione 1- using mapReduce. mapReduce è la forma generale di aggregazione che consente all'utente di fare qualsiasi cosa immaginabile e programmabile.

seguente è la soluzione mongo shell che utilizza mapReduce. Consideriamo la seguente raccolta 'st'.

{ "_id" : ObjectId("51d6d23b945770d6de5883f1"), "foo" : "foo1", "bar" : "bar1" }
{ "_id" : ObjectId("51d6d249945770d6de5883f2"), "foo" : "foo2", "bar" : "bar2" }
{ "_id" : ObjectId("51d6d25d945770d6de5883f3"), "foo" : "foo2", "bar" : "bar22" }
{ "_id" : ObjectId("51d6d28b945770d6de5883f4"), "foo" : "foo2", "bar" : "bar3" }
{ "_id" : ObjectId("51d6daf6945770d6de5883f5"), "foo" : "foo3", "bar" : "bar3" }
{ "_id" : ObjectId("51d6db03945770d6de5883f6"), "foo" : "foo4", "bar" : "bar24" }

vogliamo raggruppare per foo, e per ogni foo, contare il numero di doc, così come il numero di doc con barra contenente la sottostringa 'bar2'. cioè:

foo1: nbdoc=1, n_match = 0
foo2: nbdoc=3, n_match = 2
foo3: nbdoc=1, n_match = 0
foo4: nbdoc=1, n_match = 1

Per fare ciò, definisci la seguente funzione mappa

var mapFunction = function() {
  var key = this.foo;
  var nb_match_bar2 = 0;
  if( this.bar.match(/bar2/g) ){
    nb_match_bar2 = 1;
  }
  var value = {
    count: 1,
    nb_match: nb_match_bar2
  };

  emit( key, value );
};

e la seguente funzione di riduzione

var reduceFunction = function(key, values) {

  var reducedObject = {
    count: 0,
    nb_match:0
  };
  values.forEach( function(value) {
    reducedObject.count += value.count;
    reducedObject.nb_match += value.nb_match;
  }
  );
  return reducedObject;
};

esegui mapduce e salva il risultato nella raccolta map_reduce_result

db.st.mapReduce(mapFunction, reduceFunction, {out:'map_reduce_result'})
{
  "result" : "map_reduce_result",
  "timeMillis" : 7,
  "counts" : {
    "input" : 6,
    "emit" : 6,
    "reduce" : 1,
    "output" : 4
},
"ok" : 1,
}

Infine, possiamo interrogare la raccolta map_reduce_result, voilà! la soluzione

> db.map_reduce_result.find()
{ "_id" : "foo1", "value" : { "count" : 1, "nb_match" : 0 } }
{ "_id" : "foo2", "value" : { "count" : 3, "nb_match" : 2 } }
{ "_id" : "foo3", "value" : { "count" : 1, "nb_match" : 0 } }
{ "_id" : "foo4", "value" : { "count" : 1, "nb_match" : 1 } }

soluzione 2:utilizzo di due aggregazioni separate e unione Non fornirò dettagli per questa soluzione poiché qualsiasi utente mongo può farlo facilmente. passaggio 1:eseguire l'aggregazione, ignorando la parte che richiede regex per sommare. passaggio 2:eseguire un secondo raggruppamento di aggregazione sulla stessa chiave di quella del passaggio uno.fase 1 della pipeline:abbina l'espressione regolare;fase 2:raggruppa sulla stessa chiave del primo passaggio e conta il numero di documenti in ciascun gruppo {$sum:1};step 3:unisci il risultato del passaggio 1 e 2:per ogni chiave che compare in entrambi i risultati aggiungi il nuovo campo, se la chiave non è presente nel secondo risultato imposta la nuova chiave a 0.

Ecco! un'altra soluzione.