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

Er der en løsning for at tillade brug af et regex i Mongodb-aggregationspipelinen

Dette spørgsmål ser ud til at komme mange gange uden nogen løsning. Der er to mulige løsninger, som jeg kender:løsning 1 - ved hjælp af mapReduce. mapReduce er den generelle form for aggregering, der lader brugeren gøre alt tænkeligt og programmerbart.

følgende er mongo shell-løsningen ved hjælp af mapReduceVi overvejer følgende 'st'-samling.

{ "_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" }

vi vil gruppere efter foo, og for hver foo tælle antallet af doc, samt antallet af doc med bar, der indeholder understrengen 'bar2'. det vil sige:

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

For at gøre det skal du definere følgende kortfunktion

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

og følgende reducere funktion

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;
};

kør mapduce og gem resultatet i samlingen 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,
}

Endelig kan vi forespørge samlingen map_reduce_result, voila! løsningen

> 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 } }

løsning 2 - brug af to separate aggregeringer og mergeJeg vil ikke give detaljer for denne løsning, da enhver mongo-bruger nemt kan gøre det.trin 1:lav aggregeringen, ignorer den del, der kræver regex for at summere.trin 2:lav en anden aggregeringsgruppering på den samme nøgle som den i trin et.trin 1 af pipelinen:match det regulære udtryk;trin 2:gruppe på samme nøgle som i det første trin og tæl antallet af dokumenter i hver gruppe {$sum:1};trin 3:flet resultatet af trin 1 og 2:for hver nøgle, der vises i begge resultater, tilføj det nye felt, hvis nøglen ikke er til stede i det andet resultat, sæt den nye nøgle til 0.

Voila! en anden løsning.




  1. mongo-go-driver:indlejret OR/AND-forespørgselsfilter

  2. MongoDB-relationer for objekter

  3. Hurtigste måde at gemme et numpy array i redis

  4. Jeg prøver at køre mongod server på ubuntu :undtagelse i initAndListen:29 Databibliotek /data/db ikke fundet., afsluttes