2014-04-11 38 views
0

產品和變型價格均products.Variants.PriceMongoDB中的foreach DOC發現分鐘子集和更新

搜索最小值,其中規模較小,15%的更新

{ 
     "_id" : 23, 
     "name" : "Polo Shirt", 
     "Variants" : [ 
      { 
       "size" : "Large", 
       "Price" : 82.42 
      }, 
      { 
       "size" : "Medium", 
       "Price" : 20.82 // this should get increased by 15% 
      }, 
      { 
       "size" : "Small", 
       "Price" : 42.29 
      } 
     ] 
    }, 
{ 
     "_id" : 24, 
     "name" : "Polo Shirt 2", 
     "Variants" : [ 
      { 
       "size" : "Large", 
       "Price" : 182.42 
      }, 
      { 
       "size" : "Medium", 
       "Price" : 120.82 // this should get increased by 15% 
      }, 
      { 
       "size" : "Small", 
       "Price" : 142.29 
      } 
     ] 
    } 

我開始是這樣的。不知道這是正確的開始

db.products.find().forEach(function(product){ 
    var myArr = product.Variants; 
    print(myArr.min()); 
}); 
+0

如果你需要在你的變體中找到min,你爲什麼要迭代集合中的documetns? –

+0

我需要更新最小的一個。 – HaBo

+0

集合中所有文檔的最小值還是文檔中所有變體的最小值? –

回答

0

這裏有一個問題,你不能在一個更新語句識別的陣列的位置更新使用「最低」的值,所以你是正確的採用您當前的方法。

有爭議的是,更好的方法是預先確定哪個元素是最小元素,並將其傳遞給更新。您可以使用.aggregate()做到這一點:

var result = db.products.aggregate([ 
    { "$unwind": "$Variants" }, 
    { "$sort": { "_id": 1, "Variants.price" } } 
    { "$group": { 
     "_id": "$_id", 
     "size": { "$first": "$Variants.size" }, 
     "price": { "$first": "$Variants.price" } 
    }}, 
    { "$project": { 
     "size": 1, 
     "price": 1, 
     "adjusted": { "$multiply": [ "$price", 1.15 ] } 
    }} 
]) 

所以當然是,但只有與簡單地將最低變項細節每件產品的結果,但那麼你可以使用的結果是這樣的:

result.result.forEach(function(doc) { 
    db.products.update(
     { 
      "_id": doc._id, 
      "Variants": { "$elemMatch": { 
       "size": doc.size, 
       "price": doc.price 
      }} 
     }, 
     { 
      "$set": { 
       "Variants.$.price": doc.adjusted 
      } 
     } 
    } 
}) 

這不是最好的形式,但它至少會消除一些迭代數組的開銷,並允許在服務器硬件上執行計算,這可能是客戶端的更高規格。

雖然在MongoDB 2.6及更高版本中可以使用某些功能,但它看起來並不算太多。值得注意的是,聚合獲得一個響應的遊標,你現在也可以做"bulk updates"。所以,形式是可以改變的,像這樣:

var cursor = db.products.aggregate([ 
    { "$unwind": "$Variants" }, 
    { "$sort": { "_id": 1, "Variants.price" } } 
    { "$group": { 
     "_id": "$_id", 
     "size": { "$first": "$Variants.size" }, 
     "price": { "$first": "$Variants.price" } 
    }}, 
    { "$project": { 
     "size": 1, 
     "price": 1, 
     "adjusted": { "$multiply": [ "$price", 1.15 ] } 
    }} 
]); 

var batch = []; 

while (var doc = cursor.next()) { 

    batch.push({ 
     "q": { 
      "_id": doc._id, 
      "Variants": { "$elemMatch": { 
       "size": doc.size, 
       "price": doc.price 
      }} 
     }, 
     "u": { 
      "$set": { 
       "Variants.$.price": doc.adjusted 
      } 
     } 
    }); 

    if (batch.length % 500 == 0) { 
     db.command({ "update": "products", "updates": batch }); 
    } 
} 

db.command({ "update": "products", "updates": batch }); 

所以這是在非常好的,而你還在遍歷列表中的流量,並通過電線等待響應確實被最小化。最好的部分是正在發生的批量更新(通過數學使用)每500個項目只發生一次。批次項目的最大大小實際上是16MB的BSON限制,因此您可以根據需要調整該限制。

如果您目前正在開發產品以轉移到2.6版本,那麼給出幾個很好的理由。

考慮到你正在處理「價格」問題,我將添加的唯一最後一個腳註是儘量不要使用浮點數學,而是使用整型來查找表單,而不是用它來避免很多問題。

0

這是我如何將它拉下來的。

var result = db.Products.aggregate( 
    [  { "$unwind":"$Variants" },{"$match":{"Variants.size":"small"}}, 
     { "$group": 
      {"_id":"$_id","minprice": 
       {"$min":"$Variants.price" }}}, 
       {$sort:{ _id: 1}} ]) 


       result.result.forEach(function(doc) { 

        db.Products.update({ "_id": doc._id }, 
          { "$pull": { "Variants" : { 
               "price":doc.minprice, 
               "size":"small" 
          } } } , 
          { $addToSet: { "Variants":{ 
               "price":doc.minprice*1.15, 
               "size":"small" 
          } } 

    ); 

});