2012-02-07 2 views
3

Рассмотрим следующий пример коллекции Монго:Rails & Mongoid уникальные результаты

{"_id" : ObjectId("4f304818884672067f000001"), "hash" : {"call_id" : "1234"}, "something" : "AAA"} 
{"_id" : ObjectId("4f304818884672067f000002"), "hash" : {"call_id" : "1234"}, "something" : "BBB"} 
{"_id" : ObjectId("4f304818884672067f000003"), "hash" : {"call_id" : "1234"}, "something" : "CCC"} 
{"_id" : ObjectId("4f304818884672067f000004"), "hash" : {"call_id" : "5555"}, "something" : "DDD"} 
{"_id" : ObjectId("4f304818884672067f000005"), "hash" : {"call_id" : "5555"}, "something" : "CCC"} 

Я хотел бы запросить эту коллекцию и получить только первую запись для каждого «call_id», другими словами, я пытаюсь получить уникальные результаты на основе «call_id». Я пытался использовать .distinct метод:

@result = Myobject.all.distinct('hash.call_id') 

но результирующий массив будет содержать только уникальные поля call_id:

["1234", "5555"] 

и мне тоже нужно все другие поля. Можно ли сделать запрос, как этот ?:

@result = Myobject.where('hash.call_id' => Myobject.all.distinct('hash.call_id')) 

Благодарности

ответ

7

Вы не можете просто вернуть документ (или подмножество), используя отчетливый. В соответствии с documentation он возвращает только отдельный массив значений на основе данного ключа. Но вы можете добиться этого с помощью карты-свертка

var _map = function() { 
    emit(this.hash.call_id, {doc:this}); 
} 

var _reduce = function (key, values) { 
    var ret = {doc:[]}; 
    var doc = {}; 
    values.forEach(function (value) { 
    if (!doc[value.doc.hash.call_id]) { 
      ret.doc.push(value.doc); 
      doc[value.doc.hash.call_id] = true; //make the doc seen, so it will be picked only once 
     } 
    }); 
    return ret; 
} 

выше код сам объяснительный, на функцию отображения я группируя его по ключевым hash.call_id и возвращая весь документ, поэтому он может быть обработан уменьшить Funcition.

В функции уменьшения, просто пройдите по сгруппированному результирующему набору и выберите только один элемент из сгруппированного набора (среди множества повторяющихся значений ключа - отличное моделирование).

Наконец создать тестовые данные

> db.disTest.insert({hash:{call_id:"1234"},something:"AAA"}) 
> db.disTest.insert({hash:{call_id:"1234"},something:"BBB"}) 
> db.disTest.insert({hash:{call_id:"1234"},something:"CCC"}) 
> db.disTest.insert({hash:{call_id:"5555"},something:"DDD"}) 
> db.disTest.insert({hash:{call_id:"5555"},something:"EEE"}) 
> db.disTest.find() 
{ "_id" : ObjectId("4f30a27c4d203c27d8f4c584"), "hash" : { "call_id" : "1234" }, "something" : "AAA" } 
{ "_id" : ObjectId("4f30a2844d203c27d8f4c585"), "hash" : { "call_id" : "1234" }, "something" : "BBB" } 
{ "_id" : ObjectId("4f30a2894d203c27d8f4c586"), "hash" : { "call_id" : "1234" }, "something" : "CCC" } 
{ "_id" : ObjectId("4f30a2944d203c27d8f4c587"), "hash" : { "call_id" : "5555" }, "something" : "DDD" } 
{ "_id" : ObjectId("4f30a2994d203c27d8f4c588"), "hash" : { "call_id" : "5555" }, "something" : "EEE" } 

и управление этой карты уменьшить

> db.disTest.mapReduce(_map,_reduce, {out: { inline : 1}}) 
{ 
    "results" : [ 
     { 
      "_id" : "1234", 
      "value" : { 
       "doc" : [ 
        { 
         "_id" : ObjectId("4f30a27c4d203c27d8f4c584"), 
         "hash" : { 
          "call_id" : "1234" 
         }, 
         "something" : "AAA" 
        } 
       ] 
      } 
     }, 
     { 
      "_id" : "5555", 
      "value" : { 
       "doc" : [ 
        { 
         "_id" : ObjectId("4f30a2944d203c27d8f4c587"), 
         "hash" : { 
          "call_id" : "5555" 
         }, 
         "something" : "DDD" 
        } 
       ] 
      } 
     } 
    ], 
    "timeMillis" : 2, 
    "counts" : { 
     "input" : 5, 
     "emit" : 5, 
     "reduce" : 2, 
     "output" : 2 
    }, 
    "ok" : 1, 
} 

Вы получаете первый документ на определенном наборе. Вы можете сделать то же самое в Mongoid на первом stringify карты/уменьшить функции и вызвать MapReduce как этого

MyObject.collection.mapreduce(_map,_reduce,{:out => {:inline => 1},:raw=>true }) 

Надеется, что это помогает

Смежные вопросы