MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Има ли заобиколно решение, което да позволи използването на регулярен израз в тръбопровода за агрегиране на Mongodb

Този въпрос изглежда идва много пъти без решение. Има две възможни решения, които знам:решение 1 - използване на mapReduce. mapReduce е общата форма на агрегиране, която позволява на потребителя да прави всичко, което може да се въобрази и програмируемо.

Следното е решението на mongo shell, използващо mapReduce. Разглеждаме следната колекция '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" }

искаме да групираме по foo и за всяко foo да преброим броя на документи, както и броя на документи с лента, съдържаща подниза 'bar2'. това е:

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

За да направите това, дефинирайте следната функция за карта

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

и следната функция за намаляване

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

стартирайте mapduce и съхранете резултата в колекцията 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,
}

И накрая, можем да отправим запитване към колекцията map_reduce_result, готово! решението

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

решение 2- използване на две отделни агрегации и сливане. Няма да давам подробности за това решение, тъй като всеки потребител на mongo може лесно да го направи. стъпка 1:направете агрегацията, като игнорирате частта, която изисква regex за сумиране. стъпка 2:направете второ групиране на агрегации на същия ключ като този от първа стъпка.етап 1 на тръбопровода:съответства на регулярния израз;етап 2:групирайте на същия ключ като в първата стъпка и пребройте броя документи във всяка група {$sum:1};стъпка 3:обединете резултата от стъпка 1 и 2:за всеки ключ, който се появява и в двата резултата, добавете новото поле, ако ключът не присъства във втория резултат, задайте новия ключ на 0.

Ето! друго решение.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. $strLenBytes срещу $strLenCP в MongoDB:Каква е разликата?

  2. Съставен ключ MongoDB

  3. Съхраняване и заявяване на JSON от база данни

  4. Как да групирате по документи по седмица в mongodb

  5. Mongoose не записва данни в MongoDB