2016-06-29 24 views
5

Tôi có một số items bộ sưu tập như thế này:MongoDB - tổng hợp và nối kết quả vào nhóm

[ 
    { name: 'item1', description: 'description #1', categories: 'cat_A; cat_B'}, 
    { name: 'item2', description: 'description #2', categories: 'cat_B'}, 
    { name: 'item3', description: 'description #3', categories: 'cat_C; cat_B'}, 
    { name: 'item4', description: 'description #4', categories: 'cat_B; cat_A'}, 
    { name: 'item5', description: 'description #5', categories: 'cat_B'}, 
    { name: 'item6', description: 'description #6', categories: 'cat_D'} 
] 

Tôi muốn tìm và lọc kết quả theo loại. Tôi tạo ra truy vấn Mongo:

db.getCollection('items') 
    .aggregate([ 
     { 
      $match: { 
       categories: {$in: [/cat_a/i, /cat_b/i]} 
      } 
     }, { 
      $group: { 
       _id: "$categories", 
       items: { $push: { name: "$name", description: '$description' } } 
      } 
     } 
    ]) 

Vì vậy, nó sẽ trả về cho tôi này:

result : [ 
    { 
     "_id" : "cat_B; cat_C", 
     "items" : [ 
      { 
       "name" : "item3", 
       "description" : "description #3" 
      } 
     ] 
    }, { 
     "_id" : "cat_B; cat_A", 
     "items" : [ 
      { 
       "name" : "item4", 
       "description" : "description #4" 
      } 
     ] 
    }, { 
     "_id" : "cat_B", 
     "items" : [ 
      { 
       "name" : "item2", 
       "description" : "description #2" 
      }, 
      { 
       "name" : "item5", 
       "description" : "description #5" 
      } 
     ] 
    }, { 
     "_id" : "cat_A; cat_B", 
     "items" : [ 
      { 
       "name" : "item1", 
       "description" : "description #1" 
      } 
     ] 
    } 
] 

Những gì tôi muốn đạt được là:

result : [ 
    { 
     "_id" : "cat_A", 
     "items" : [ 
      { 
       "name" : "item1", 
       "description" : "description #1" 
      }, 
      { 
       "name" : "item4", 
       "description" : "description #4" 
      } 
     ] 
    }, { 
     "_id" : "cat_B", 
     "items" : [ 
      { 
       "name" : "item1", 
       "description" : "description #1" 
      }, 
      { 
       "name" : "item2", 
       "description" : "description #2" 
      }, 
      { 
       "name" : "item3", 
       "description" : "description #3" 
      }, 
      { 
       "name" : "item4", 
       "description" : "description #4" 
      }, 
      { 
       "name" : "item5", 
       "description" : "description #5" 
      } 
     ] 
    } 
] 

Là có thể trong truy vấn Mongo tinh khiết?

Trả lời

2

Với khung tổng hợp, bạn sẽ cần một cơ chế để tách chuỗi categories thành một tập hợp riêng biệt nhưng nhà khai thác như vậy chưa tồn tại; gần nhất bạn sẽ nhận được là nhà điều hành substr yêu cầu biết chỉ mục vị trí chỉ mục và số ký tự được chỉ định cho chuỗi con được trích xuất, điều này gần như không thể. Do đó, đề xuất lưu trữ các danh mục dưới dạng một mảng các tên danh mục riêng biệt.

- EDIT -

Nếu bạn muốn giữ lại các lĩnh vực categories như là sau đó tôi sẽ đề nghị bạn tạo thêm một lĩnh vực mà các cửa hàng danh sách các loại, sau đó bạn có thể chạy các đường ống kết hợp trên trường đó để có được kết quả mong muốn.

Hãy sử dụng một ví dụ để chứng minh phương pháp trên:

Thay đổi schema

a) Nếu sử dụng MongoDB v3.0 hoặc dưới đây:

var bulk = db.items.initializeOrderedBulkOp(), 
    counter = 0; 

db.items.find({}).forEach(doc) { 
    var categoriesList = doc.categories.replace(/^\s+|\s+$/g,"").split(/\s*;\s*/); 
    bulk.find({ "_id": doc._id }) 
     .updateOne({ 
      "$set": { "categoriesList": categoriesList } 
     }); 
    counter++; 

    if (counter % 1000 == 0) { 
     bulk.execute(); 
     bulk = db.items.initializeOrderedBulkOp(); 
    } 
} 

if (counter % 1000 != 0) bulk.execute(); 

b) Nếu sử dụng MongoDB v3.2.X trở lên:

var cursor = db.items.find({}), 
    bulkUpdateOps = []; 

cursor.forEach(function(doc){ 
    var categoriesList = doc.categories.replace(/^\s+|\s+$/g,"").split(/\s*;\s*/); 
    bulkUpdateOps.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { "$set": { "categoriesList": categoriesList } } 
     } 
    }); 

    if (bulkUpdateOps.length == 1000) { 
     db.items.bulkWrite(bulkUpdateOps); 
     bulkUpdateOps = []; 
    } 
});   

if (bulkUpdateOps.length > 0) db.items.bulkWrite(bulkUpdateOps); 

Chạy tập hợp trên schema mới

db.items.aggregate([ 
    { "$match": { "categoriesList": { "$in": ['cat_A', 'cat_B'] } } }, 
    { "$unwind": "$categoriesList" }, 
    { 
     "$group": { 
      "_id": "$categoriesList", 
      "items": { "$push": { "name": "$name", "description": '$description' } } 
     } 
    } 
]) 
+1

chúng ta có thể sử dụng 'chia ("")' và 'trim' cho một dọn dẹp nhỏ. – profesor79

+0

Thật không may, tôi không thể sửa đổi bất kỳ trường nào trong bộ sưu tập này và tôi cần giữ 'danh mục' làm chuỗi. – zucker

+0

Sau đó, tạo một trường bổ sung lưu trữ bộ danh mục riêng biệt và bạn có thể giữ trường danh mục ban đầu như cũ. Khi bạn chạy đường ống tổng hợp, bạn có thể '$ relax' và nhóm theo trường mới. – chridam

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