2012-08-31 22 views
11

Tôi đang cố gắng làm điều gì đó mà tôi nghĩ là khá đơn giản. Giả sử tôi có một loạt các bản ghi trong mongo có khóa chung và số thuộc tính thay đổi. Tôi muốn chọn tất cả các thuộc tính và nhóm theo tên trên các bản ghi. Ví dụChọn * nhóm theo tập hợp mongo

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

Tôi muốn tạo ra một CSV mà trông như thế này:

Name  X Y Z 
George 5 3 9 
Rob  12 2 

Cố gắng

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

Đáng tiếc là tôi lấy lại tất cả những cái tên như hồ sơ nhưng không phải là công đoàn của tất cả các thuộc tính có thể.

Trả lời

11

Nếu bạn muốn kết hợp các thuộc tính, bạn sẽ cần phải thêm các thuộc tính đó vào số group. Ví dụ, sử dụng $addToSet để tìm các giá trị độc đáo của x, y, thuộc tính z được phân nhóm theo từng tên:

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

Returns:

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

Cảm ơn, tôi đã làm một điều tương tự bằng cách sử dụng $ push và có vẻ như nó hoạt động. Câu hỏi tiếp theo của tôi sẽ là liệu từ đây có cách nào tốt nhất là xuất dữ liệu sang CSV phẳng, giải phóng các mảng nội bộ trong tập kết quả? –

+0

Tôi đang sử dụng pymongo và python để tạo csv. Vấn đề còn lại là khi tôi sử dụng $ addToSet, tôi tạo mảng kết quả cho mỗi khóa, ngay cả khi chỉ có một giá trị riêng biệt cho mỗi cặp giá trị khóa. Điều này sau đó làm cho quá trình làm phẳng để csv rất cồng kềnh. Có cách nào để tránh tạo mảng các giá trị quan trọng không? –

+1

@RogerSanchez: '$ addToSet' hoặc' $ push' sẽ trả về giá trị mảng, vì vậy bạn sẽ phải thực hiện một số thao tác xoa bóp trong quá trình xuất CSV hoặc xem xét một hàm tổng hợp khác. Ví dụ: nếu tất cả các giá trị là số và bạn chỉ có một giá trị duy nhất cho mỗi trường, bạn có thể thoát khỏi bằng cách sử dụng ['$ max'] (http://docs.mongodb.org/manual/reference/aggregation/) #_S_max) thay thế. Nếu các giá trị kết quả là * đôi khi * mảng, bạn sẽ phải tranh luận trong mã của bạn. Dưới đây là một ví dụ về gist của Python có thể giúp: [làm phẳng các mảng tăng thêm thành các chuỗi được trích dẫn trong CSV] (https://gist.github.com/a39b087da394b746e4fe). – Stennie

0

Đây là một cách khác để làm việc đó:

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

Bạn sẽ nhận được một cái gì đó câu trả lời như thế này (không phải là chính xác sản lượng):

0.123.
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

Trong khi 'nhóm' là một lựa chọn khả thi miễn là bộ sưu tập của bạn không bị phân mảnh, bạn không nên ' t sử dụng các ví dụ PHP trong các câu hỏi không phải PHP. – JohnnyHK

+1

@JohnnyHK: Tôi đã tìm kiếm nó trong một thời gian dài, tôi có liên kết này trong ngăn xếp, nhưng nó không trả lời đúng, vì vậy khi tôi tìm thấy câu trả lời tôi đăng nó ở đây, một số có thể tìm thấy nó hữu ích, Nếu bạn thực sự muốn tôi xóa tôi có thể làm điều đó. –

+0

Tùy thuộc vào bạn, nhưng 'aggregate' là một giải pháp tốt hơn trong trường hợp này và các ví dụ phải ở dạng JavaScript nếu có thể vì đó là ngôn ngữ mong muốn 'bản địa'. Đừng lo, chỉ cần cho bạn biết. – JohnnyHK

-1

sử dụng $addToSet vào nhóm, nó sẽ làm việc

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

Các giải pháp từ Stennie đòi hỏi bạn phải biết chính xác mà các thuộc tính bạn muốn trở về từ mỗi mục tương ứng trong bộ sưu tập bạn đang truy vấn. Đây không phải lúc nào cũng vậy.

Chúng tôi phải giải quyết vấn đề này trong ứng dụng Groovy on Grails mà chúng tôi đang viết.

Chúng tôi đã viết một phương pháp như thế này để xử lý các "tìm thấy bằng X" yêu cầu:

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

Và sau đó gọi nó trong mã của chúng tôi như sau:

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

này hoạt động bằng cách đi qua các kết quả của truy vấn ban đầu cho hàm javascript ở cuối GroupCommand. Mongo chỉ trả về các thuộc tính bạn chỉ định trong truy vấn ban đầu và không có gì khác, vì vậy bạn phải lặp lại kết quả lần thứ hai, điền chúng với phần còn lại của dữ liệu từ mongo.

Các vấn đề liên quan