2015-10-22 12 views
5

Aşağıdaki örnek veri kümesinde minimum query ve maximum query almak için bir sorgum var. Davam alanları içinde isimleri product_1, product_2 ... Bir fikrim almıyorumMongoDB: Dinamik alan adı ile iç içe nesnede en az, en çok arama yapın.

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

nasıl ben Mongo yapabilirsiniz altında nereye alan adları dinamiktir, gelecekte gelir gibi diğer olabilir, dinamiktir ürünler aynı id için product_4 ve product_5 olarak oluşturulmaktadır.

Ben orderDelivered:16 & orderCancelled:0 olacak Yukarıdaki belge sonucu örneğin, orderCancelled bana orderDelivered için minimum değeri ve maksimum değer veren bir sorgu gerekir.
Herhangi bir fikir için teşekkürler.

+0

Neden bir diziye ürünlerinizi koymayın: verir

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" } } } }} ]) 

? –

+0

@DmytroShevchenko seni anlamadım. Aslında bir başka davada "ürün adı" ile sipariş edilen siparişi verebiliyorum. Peki senin durumunda tasarım ne olacak? – Shams

+0

Lütfen cevabımdaki veri yapısı örneğine bir bakın. "Ürün adı" ile sipariş edilen "sipariş verilmiş" için ne anlama geldiğini açıklayabilir misiniz? –

cevap

1

tüm ürün belgeleri bir dizi vardır, böylece belgenizi yeniden olmalıdır:

{ 
    "_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 
     } 
    ] 
} 

Sonra bu gibi normal max/dak sorgu oluşturmak mümkün olacak:

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

Belge yapısını nasıl değiştireceğiniz gösteriliyor? – styvane

+2

@ user3100115 Mevcut veriler ayrı bir araç kullanılarak değiştirilmelidir. Böyle bir aracı tartışmanın konu dışı olacağına inanıyorum. –

+0

Hayır bunu bir güncelleştirme ile yapabilirsin – styvane

2

You Belgelerinizi güncelleyerek bunları değiştirmeniz gerekir. product_ ile başlayan tüm alanın adıyöntemi ve $unset kullanarak her bir belgeye geçmeniz gerekir. Buradan, $set güncelleme operatörünü kullanan ürün dizisi olan products numaralı yeni alanları eklemeniz gerekecektir. Yani maksimum verim için belgelerinizi güncellemek için "bulk" işlemleri kullanmalıdır söyleniyor

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(); 
} 

artık şu şekilde görünecek belgeler:

{ 
     "_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 
       } 
     ] 
} 

Sonra .aggregate() yöntemi kullanarak toplama sorgusu gelir:

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

Hangi değerler döner:

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

bunu yapmak çok daha iyi bir yol olduğunu da $project aşamasında $max ve $min kullanabilirsiniz çünkü orada ilk $unwind sizin diziye gerek.

{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivered" : 6 } 
İlgili konular