2014-06-30 17 views
7

Tôi đang gặp sự cố khi định lại lại tài liệu của mình trong khi tổng hợp để nhóm. Về cơ bản tôi muốn đẩy các mục vào các trường tùy theo loại của chúng. Tôi có một cấu trúc như sau:MongoDB dự án chọn lọc tổng hợp

_id: P1 
    entities: [{type: A, val: X}, {type: B, val: X}, {type: A, val: Y}] 
    ... 

Tôi muốn $ thư giãn và dự án $ các thực thể để có được một cấu trúc như:

_id: P1 
    A: [X] 
    B: [] 
_id: P1 
    A: [Y] 
    B: [] 
_id: P1 
    A: [] 
    B: [X] 

vì vậy tôi có thể thực hiện một nhóm bởi A hoặc B hoặc cả hai , tức là

$group: { 
    _id: { 
     A: $A, 
     B: $B 
    } 
    count: {$sum : 1} 

tôi nghĩ tôi chỉ có thể làm:

$unwind: $entities 
$project: { 
    id: §id 
    A: {"$cond":[{"$eq":["$type","A"]},"$code"]} 
    B: {"$cond":[{"$eq":["$type","B"]},"$code"]} 
} 
$group: { 
    _id: "$id" 
    A: {$addToSet : "$A"} 
} 

hoặc không có một cái gì đó giống như

$unwind: $entities 
$group: { 
    _id: "$id" 
    A: {"$cond":[{"$eq":["$type","A"]},$push: "$code", null]} 
    ... 
} 

nhưng cả hai phiên bản thất bại bởi vì tôi không thể làm gì trên khác và tôi đã không quản lý để sử dụng $ đẩy bên trong một điều kiện. Gần nhất tôi nhận được là dự án tùy thuộc vào loại, nhưng kể từ khi tôi không thể tìm thấy một cách không thêm bất cứ điều gì để lĩnh vực này khi không có trận đấu, tôi kết thúc với:

_id: P1 
    A: [X,null,Y] 
    B: [null,X,null] 

mà messes lên đếm. Ý tưởng thứ hai của tôi là lọc các mảng để loại bỏ null. Nhưng tôi đã không tìm thấy một cách để loại bỏ các thực thể, bởi vì một lần nữa $ cond sẽ không cho phép tôi chỉ định một trường hợp rỗng/"không làm gì" khác.

Tôi có cảm giác nó có thể hoạt động với nhóm theo loại và nội dung phù hợp với các loại được yêu cầu, nhưng vì tôi có nhiều loại và nhóm tùy ý dẫn đến việc nhóm cây, điều này có thể trở nên rất phức tạp. Ý tưởng hay gợi ý cho những sai lầm sẽ rất được hoan nghênh.

Cảm ơn bạn

EDIT: Các giải pháp dựa trên anwser chấp nhận

tôi phải hơi thích ứng với nó, để lọc những trường hợp tất cả các nội dung của một loại là null, bởi vì nếu không nó đã có bị mất trong quá trình kết hợp và bởi vì tôi muốn giữ kiến ​​thức đó. Cảm ơn!

{$project:{ 
    A: {$cond: [ 
     {$eq: ["$A", [false]]}, 
     ["N/A"], 
     "$A" 
    ]}, 
    B: {$cond: [ 
     {$eq: ["$B", [false]]}, 
     ["N/A"], 
     "$B" 
    ]}, 
}}, 
{ "$unwind": "$A" }, 
{ "$match": { "A": { "$ne": false } } }, 
{ "$group": { 
    "_id": "$_id", 
    "A": { "$push": "$A" }, 
    "B": { "$first": "$B" } 
}}, 
{ "$unwind": "$B" }, 
{ "$match": { "B": { "$ne": false } } }, 
{ "$group": { 
    "_id": "$_id", 
    "A": { "$first": "$A" }, 
    "B": { "$push": "$B" } 
}} 
+2

Kết quả _desired_ của bạn là gì? –

Trả lời

13

Bạn dường như đi đúng hướng, có những cách tiếp cận khác nhau để chỉ loại bỏ những giá trị của false từ có điều kiện. Bạn không thể có nó trả lại không có gì, nhưng bạn cn thoát khỏi các giá trị bạn không muốn.

Nếu bạn thực sự muốn "bộ" và bạn có MongoDB 2.6 hoặc cao hơn có sẵn, sau đó về cơ bản bạn lọc ra các false giá trị sử dụng $setDifference:

db.entities.aggregate([ 
    { "$unwind": "$entities" }, 
    { "$group": { 
     "_id": "$_id", 
     "A": { 
      "$addToSet": { 
       "$cond": [ 
        { "$eq": [ "$entities.type", "A" ] }, 
        "$entities.val", 
        false 
       ] 
      } 
     }, 
     "B": { 
      "$addToSet": { 
       "$cond": [ 
        { "$eq": [ "$entities.type", "B" ] }, 
        "$entities.val", 
        false 
       ] 
      } 
     } 
    }}, 
    { "$project": { 
     "A": { 
      "$setDifference": [ "$A", [false] ] 
     }, 
     "B": { 
      "$setDifference": [ "$B", [false] ] 
     } 
    }} 
]) 

Hoặc cũng giống như một bước sử dụng toán tử $map bên $project:

db.entities.aggregate([ 
    {"$project": { 
     "A": { 
      "$setDifference": [ 
       { 
        "$map": { 
         "input": "$entities", 
         "as": "el", 
         "in": { 
          "$cond": [ 
           { "$eq": [ "$$el.type", "A" ] }, 
           "$$el.val", 
           false 
          ] 
         } 
        } 
       }, 
       [false] 
      ] 
     }, 
     "B": { 
      "$setDifference": [ 
       { 
        "$map": { 
         "input": "$entities", 
         "as": "el", 
         "in": { 
          "$cond": [ 
           { "$eq": [ "$$el.type", "B" ] }, 
           "$$el.val", 
           false 
          ] 
         } 
        } 
       }, 
       [false] 
      ] 
     } 
    }} 
]) 

Hoặc nếu không thì ở lại với chung $unwind$match nhà khai thác để lọc các bộ lọc này:

db.entities.aggregate([ 
    { "$unwind": "$entities" }, 
    { "$group": { 
     "_id": "$_id", 
     "A": { 
      "$push": { 
       "$cond": [ 
        { "$eq": [ "$entities.type", "A" ] }, 
        "$entities.val", 
        false 
       ] 
      } 
     }, 
     "B": { 
      "$push": { 
       "$cond": [ 
        { "$eq": [ "$entities.type", "B" ] }, 
        "$entities.val", 
        false 
       ] 
      } 
     } 
    }}, 
    { "$unwind": "$A" }, 
    { "$match": { "A": { "$ne": false } } }, 
    { "$group": { 
     "_id": "$_id", 
     "A": { "$push": "$A" }, 
     "B": { "$first": "$B" } 
    }}, 
    { "$unwind": "$B" }, 
    { "$match": { "B": { "$ne": false } } }, 
    { "$group": { 
     "_id": "$_id", 
     "A": { "$first": "$A" }, 
     "B": { "$push": "$B" } 
    }} 
]) 

Sử dụng $push cho các mảng thông thường hoặc $addToSet cho các bộ duy nhất.

+1

Tuyệt vời awnser cảm ơn một triệu :) Các nhà điều hành $ setDifference sẽ là hoàn hảo (tôi đã không nhìn thấy nó), nhưng thật đáng buồn chúng tôi không chạy mongo 2.6. Grr .. Tôi đã sử dụng phiên bản thứ hai với một chỉnh sửa nhỏ (xem chỉnh sửa câu hỏi gốc để tham khảo trong tương lai) – user1437515

+0

Truy vấn trở nên phức tạp đến mức kết thúc tốt hơn để nhóm các kết quả sau đó để cho mongodb làm điều đó. – kappaallday

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