2012-08-31 18 views
11

Ben oldukça basit olduğunu düşündüğüm bir şeyi yapmaya çalışıyorum. Ortak bir anahtar ve değişken sayıda öznitelikleri olan Mongo'da bir dizi kayıt olduğunu varsayalım. Kayıtlardaki tüm öznitelikleri ve grup isimlerini seçmek istiyorum. ÖrneğinMongo kümelemesinde * grubu seçin

{ Name: George, x: 5, y: 3 } 
{ Name: George, z: 9 } 
{ Name: Rob, x: 12, y: 2 } 

ben şöyle bir CSV üretmek istiyorum:

Name  X Y Z 
George 5 3 9 
Rob  12 2 

Maalesef

DB.data.aggregate({ $group : { _id : "$Name" } }) 

çalıştı tüm kayıtları gibi isimler ama değil birliğe geri almak tüm olası özellikler.

cevap

11

Öznitelikleri birleştirmek isterseniz, bunları group'a eklemeniz gerekir.

db.data.aggregate(
    { $group : { 
      _id : "$Name", 
      x: { $addToSet: "$x" }, 
      y: { $addToSet: "$y" }, 
      z: { $addToSet: "$z" }, 
    }} 
) 

İade: Örneğin, her isim göre gruplandırılmış x, y, z niteliklerin benzersiz değerleri bulmak için $addToSet kullanarak İşte

{ 
    "result" : [ 
     { 
      "_id" : "Rob", 
      "x" : [ 
       12 
      ], 
      "y" : [ 
       2 
      ], 
      "z" : [ ] 
     }, 
     { 
      "_id" : "George", 
      "x" : [ 
       5 
      ], 
      "y" : [ 
       3 
      ], 
      "z" : [ 
       9 
      ] 
     } 
    ], 
    "ok" : 1 
} 
+0

Teşekkürler, $ push kullanarak benzer bir şey yaptım ve işe yarıyor. Benim takip sorum, verileri, sonuç kümesindeki iç dizileri çözerek, düz CSV'ye vermenin en iyi yolunun olup olmadığıdır. –

+0

csv oluşturmak için pymongo ve python kullanıyorum. Geriye kalan sorunlardan biri, $ addToSet kullandığımda, her bir anahtar değer çifti için tek bir değer olsa bile, her anahtar için sonuç dizileri oluşturduğumdur. Bu daha sonra csv düzleştirme süreci çok hantal hale getirir. Anahtar değerlerin dizilerini oluşturmamanın bir yolu var mı? –

+1

@RogerSanchez: '$ addToSet' veya' $ push' dizi değerlerini döndürecek, bu yüzden CSV dışa aktarma işleminizde biraz masaj yapmak veya farklı bir toplama işlevi düşünmek zorunda kalacaksınız. Örneğin, tüm değerler sayısalsa ve her alan için yalnızca bir tek değeriniz varsa, ['$ max'] 'ı kullanarak uzaklaşabilirsiniz (http://docs.mongodb.org/manual/reference/aggregation/ Bunun yerine #_S_max). Sonuç değerleri * bazen * diziler ise, kodunuzda sıkışmak zorunda kalacaksınız. İşte size yardımcı olabilecek bir Python oyunu örneği: [agg dizilerini CSV'de alıntılanmış dizelere düzleştirme] (https://gist.github.com/a39b087da394b746e4fe). – Stennie

0

bunu yapmanın başka bir yoludur:

$connection = 'mongodb://localhost:27017'; 
$con  = new Mongo($connection); // mongo connection 

$db   = $con->test; /// database 
$collection = $db->prb; // table 

$keys  = array("Name" => 1,"x"=>1,"y"=>1,"z"=>1); 

// set intial values 
$initial = array("count" => 0); 

// JavaScript function to perform 
$reduce  = "function (obj, prev) { prev.count++; }"; 

$g   = $collection->group($keys, $initial, $reduce); 

echo "<pre>"; 
print_r($g); 

Sen cevap böyle bir şey (değil tam çıkış) alacak:

Gruba
Array 
(
    [retval] => Array 
     (
      [0] => Array 
       (
        [Name] => George 
        [x] => 
        [y] => 
        [z] => 
        [count] => 2 
       ) 

      [1] => Array 
       (
        [Name] => Rob 
        [x] => 
        [y] => 
        [z] => 
        [count] => 1 
       ) 

     ) 

    [count] => 5 
    [keys] => 3 
    [ok] => 1 
) 
+1

Koleksiyonunuz keskinleşmediği sürece "grup" geçerli bir seçenek olsa da, PHP dışı sorularda PHP örneklerini kullanmayın. – JohnnyHK

+1

@JohnnyHK: Bunu uzun zamandır arıyordum, bu bağlantıyı yığın halinde aldım, ama bana doğru cevabı vermedim, bu yüzden burada yayınladığım cevabı bulduğumda, bir kişi yararlı olabilir. gerçekten silmemi istiyorum bunu yapabilirim. –

+0

Size kalmış, fakat 'aggregate' bu durumda daha iyi bir çözümdür ve mümkünse örnekler 'native' mongo dili olduğu için JavaScript'te olmalıdır. Endişelenme, sadece bilmeni sağla. – JohnnyHK

-1

kullanım $addToSet, bu Stennie gelen çözüm size sorguladığınız koleksiyonunda her eşleşen öğeye dönmek istediğiniz nitelikleri tam olarak bilmek gerektirir

db.data.aggregate(
    { $group : { 
      _id : "$Name", 
      x: { $addToSet: "$x" }, 
      y: { $addToSet: "$y" }, 
      z: { $addToSet: "$z" }, 
    }} 
) 
0

çalışacaktır. Bu her zaman böyle değildir.

Bu sorunu, yazdığımız bir Groovy Grails uygulamasında çözmek zorundaydık.

Böyle bir yöntem işlemek için yazdığı istekleri "X ile bulmak":

private List<DBObject> findDistinctPages(Map by) { 
    def command = 
     new GroupCommand(
       (DBCollection) db.pages, 
       new BasicDBObject(['url': 1]), 
       new BasicDBObject(by), 
       new BasicDBObject([:]), 
       'function (current, result) { for(i in current) { result[i] = current[i] } }', 
       '' 
     ) 
    db.pages.group(command).sort { it.title } 
} 

Ve sonra şöyle bizim kodunda bunun çağırır: Bu işler

def pages = findDistinctPages([$or: [[type: 'channel'], [type: 'main']]]) 

sonuçları geçirerek GroupCommand'ın sonunda javascript işlevine ilk sorgulama. Mongo, yalnızca ilk sorguda belirttiğiniz öznitelikleri döndürür ve başka bir şey yoktur, bu nedenle sonuçları ikinci kez tekrarlamak zorunda kalırsınız, bu da onları mongo'dan gelen verilerin geri kalanıyla doldurur.