0

製品とバリエーションの価格

products.Variants.Priceサイズが小さいすべての最小値を見つけて、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());
});
4

2 に答える 2

0

ここには、位置更新で使用する配列内の「最小」値を単一の update ステートメントで特定できないという問題があるため、現在のアプローチでは正しい方法です。

より良いアプローチは、どの要素が最小要素であるかを事前に決定し、これを更新に渡すことであると主張できます。次を使用してこれを行うことができます.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 以降で利用可能ないくつかの機能を取り入れるまでは、それほど多くはないように見えます。特に、その集計は応答のカーソルを取得し、 「一括更新」も実行できるようになりました。したがって、フォームは次のように変更できます。

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 アイテムごとに 1 回だけ (数学的な使用法で) 発生するバッチ更新です。バッチ項目の最大サイズは、実際には 16MB の BSON 制限であるため、必要に応じて調整できます。

これは、現在 2.6 バージョンに移行する製品を開発している場合に、いくつかの正当な理由を提供します。

「価格」を扱っていることを考慮して追加する唯一の最後の脚注は、これに浮動小数点演算を使用せず、代わりに整数全体を使用する形式を探すことです。これにより、多くの問題が回避されます。

于 2014-04-12T03:45:00.750 に答える