2015-10-22 40 views
5

Tôi có truy vấn để có được minimum querymaximum query ở bên dưới bộ dữ liệu mẫu. Trong trường hợp của tôi các lĩnh vực tên là năng động, như dưới đây product_1, product_2 ...MongoDB: Tìm kiếm tối thiểu, tối đa trong đối tượng lồng nhau với tên trường động

{ 
    "_id" : NumberLong(540), 
    "product_1" : { 
      "orderCancelled" : 0, 
      "orderDelivered" : 6 
    }, 
    "product_2" : { 
      "orderCancelled" : 3, 
      "orderDelivered" : 16 
    }, 
    "product_3" : { 
      "orderCancelled" : 5, 
      "orderDelivered" : 11 
    } 
} 

tôi không nhận được một ý tưởng làm thế nào tôi có thể làm điều này trong Mongo nơi tên trường năng động, có nghĩa là trong tương lai có thể có khác sản phẩm cũng được tạo thành product_4product_5 cho cùng một id.

Tôi cần một truy vấn mà mang lại cho tôi giá trị tối thiểu cho orderDelivered và giá trị tối đa cho orderCancelled, như ví dụ trong kết quả tài liệu trên sẽ được orderDelivered:16 & orderCancelled:0.
Cảm ơn mọi ý tưởng.

+0

Tại sao bạn không đưa sản phẩm của bạn vào một mảng? –

+0

@DmytroShevchenko tôi đã không nhận được bạn. Trên thực tế trong một trường hợp khác tôi cũng có thể cung cấp cho đếm cho 'orderDelivered' bởi' tên sản phẩm'. Điều gì sẽ là thiết kế trong trường hợp của bạn? – Shams

+0

Hãy xem ví dụ về cấu trúc dữ liệu trong câu trả lời của tôi. Bạn có thể mô tả những gì bạn có nghĩa là bằng cách đếm cho 'orderDelivered' bởi' tên sản phẩm'? –

Trả lời

1

Bạn nên tái cấu trúc tài liệu của bạn để tất cả tài liệu sản phẩm đang ở trong một mảng:

{ 
    "_id": NumberLong(540), 
    products: [ 
     { 
      "name": "product_1", 
      "orderCancelled": 0, 
      "orderDelivered": 6 
     }, 
     { 
      "name": "product_2", 
      "orderCancelled": 3, 
      "orderDelivered": 16 
     }, 
     { 
      "name": "product_3", 
      "orderCancelled": 5, 
      "orderDelivered": 11 
     } 
    ] 
} 

Sau đó, bạn sẽ có thể phát hành các truy vấn max/min bình thường như thế này:

db.test.aggregate([ 
    { 
     $match: { "_id" : NumberLong(540) } 
    }, 
    { 
     $unwind: "$products" 
    }, 
    { 
     $group: { 
      _id: "$_id", 
      minDelivered: { $min: "$products.orderDelivered" }, 
      maxCancelled: { $max: "$products.orderCancelled" } 
     } 
    } 
]) 
+0

Điều gì về cách hiển thị cách thay đổi cấu trúc tài liệu? – styvane

+2

@ user3100115 dữ liệu hiện có phải được thay đổi bằng một công cụ riêng biệt. Tôi tin rằng thảo luận về một công cụ như vậy sẽ không có chủ đề ở đây. –

+0

Không, bạn có thể thực hiện việc này với bản cập nhật – styvane

2

Bạn cần phải thay đổi cấu trúc tài liệu của bạn bằng cách cập nhật chúng. Bạn sẽ cần lặp qua từng tài liệu bằng cách sử dụng phương thức .forEach sau đó $unset tên của tất cả các trường bắt đầu bằng product_. Từ đó bạn sẽ cần thêm các trường mới products là mảng sản phẩm sử dụng toán tử cập nhật $set. Điều đó đang được nói, bạn nên sử dụng "bulk" hoạt động để cập nhật tài liệu của bạn cho hiệu quả tối đa

var bulkOp = db.collection.initializeOrderedBulkOp(); 
var count = 0; 
db.collection.find().forEach(function(doc) { 
    var allproducts = []; 
    for(var key in doc) { 
     if(Object.prototype.hasOwnProperty.call(doc, key) && /^product_\d+/.test(key)) { 
      var product = {}; 
      product["name"] = key;  
      product["orderCancelled"] = doc[key]["orderCancelled"]; 
      product["orderDelivered"] = doc[key]["orderDelivered"]; 
      allproducts.push(product); 
      var unsetField = {}; 
      unsetField[key] = ""; 
      bulkOp.find({"_id": doc._id}).update({ "$unset": unsetField }); 
     }; 
     count++; 
    }; 
    bulkOp.find({"_id": doc._id}).update({ 
     "$set": { "products": allproducts } 
    }); 
    count++; 
    if(count % 500 === 0) { 
     // Execute per 500 operations and re-init 
     bulkOp.execute(); 
     bulkOp = db.collection.initializeOrderedBulkOp(); 
    } 
}) 

// clean up queues 

if(count > 0) { 
    bulkOp.execute(); 
} 

Tài liệu của bạn bây giờ sẽ trông như thế này:

{ 
     "_id" : NumberLong(542), 
     "products" : [ 
       { 
         "name" : "product_1", 
         "orderCancelled" : 0, 
         "orderDelivered" : 6 
       }, 
       { 
         "name" : "product_2", 
         "orderCancelled" : 3, 
         "orderDelivered" : 16 
       }, 
       { 
         "name" : "product_3", 
         "orderCancelled" : 5, 
         "orderDelivered" : 11 
       } 
     ] 
} 

Rồi đến truy vấn tập hợp của bạn bằng cách sử dụng phương pháp .aggregate():

db.collection.aggregate([ 
    { "$match": { "_id": 542 } }, 
    { "$unwind": "$products" }, 
    { "$group": { 
     "_id": "$_id", 
     "maxOrderCancelled": { "$max": "$products.orderCancelled"}, 
     "minOrderDelivvered": { "$min": "$products.orderDelivered"} 
    }} 
]) 

Lợi nhuận nào:

{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivvered" : 6 } 

Từ version 3.2 bạn có thể sử dụng $max$min trong giai đoạn $project của bạn mà là một cách nhiều hơn nữa tốt hơn để làm điều này bởi vì có không cần phải $unwind mảng của bạn đầu tiên.

db.collection.aggregate([ 
    { "$match": { "_id": 542 } }, 
    { "$project": { 
     "maxOrderCancelled": { 
      "$max": { 
       "$map": { 
        "input": "$products", 
        "as": "order", 
        "in": "$$orc.orderCancelled" 
       } 
      } 
     }, 
     "minOrderDelivered": { 
      "$min": { 
       "$map": { 
        "input": "$products", 
        "as": "orc", 
        "in": "$$orc.orderDelivered" 
       } 
      } 
     } 
    }} 
]) 

nào mang lại:

{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivered" : 6 } 
Các vấn đề liên quan