2012-02-07 49 views
3

考慮蒙戈收集下面的例子:導軌及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處理。

關於reduce函數,只需循環遍歷分組結果集並從分組集合(在多個重複鍵值 - 不同模擬中)中僅選取一個項目。

最後創建一些測試數據

> 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第一字符串化地圖/縮小功能和呼叫的MapReduce這樣

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

希望它可以幫助