0

ハッシュを使用して保存された埋め込みドキュメントのプロパティのクエリを MongoDB がサポートしないのはなぜですか?

たとえば、次のように作成された「invoices」というコレクションがあるとします。

db.invoices.insert(
    [
        {
            productsBySku: {
                12432: {
                    price: 49.99,
                    qty_in_stock: 4
                },
                54352: {
                    price: 29.99,
                    qty_in_stock: 5
                }
            }
        },
        {
            productsBySku: {
                42432: {
                    price: 69.99,
                    qty_in_stock: 0
                },
                53352: {
                    price: 19.99,
                    qty_in_stock: 5
                }
            }
        }
    ]
);

このような構造では、$elemMatch、ドット構文、または位置演算子 ($) を使用した MongoDB クエリは、各 productsBySku メンバーのプロパティにアクセスできません。

たとえば、次のことはできません。

db.invoices.find({"productsBySku.qty_in_stock":0});

db.invoices.find({"productsBySku.$.qty_in_stock":0});

db.invoices.find({"productsBySku.qty_in_stock":{$elemMatch:{$eq:0}}});

db.invoices.find({"productsBySku.$.qty_in_stock":{$elemMatch:{$eq:0}}});

したがって、在庫切れの製品を見つけるには、次のような $where クエリを使用する必要があります。

db.invoices.find({
    $where: function () {
        for (var i in this.productsBySku)
            if (!this.productsBySku[i].qty_in_stock)
                return this;
    }
});

技術的なレベルでは... なぜ彼らは、クエリに対してこの非常に厳しい制限を設けて MongoDB を設計したのでしょうか? 確かに、この一見重大な欠陥には何らかの技術的な理由があるに違いありません。キーを無視して、オブジェクトのリストを配列として処理できないのは、言語としての JavaScript の単なる制限ですか? それとも、これは MongoDB 内のアーキテクチャ上の決定の結果でしたか?

ちょっと興味があるんだけど。

4

2 に答える 2

3

経験則として: 通常、これらの問題は技術的な問題ではなく、データ モデリングの問題です。キーにセマンティック値を保持させることが理にかなっているユースケースをまだ見つけていません。

あなたが何かを持っていたら

'products':[
     {sku:12432,price:49.99,qty_in_stock:4},
     {sku:54352,price:29.99,qty_in_stock:5}
 ]

それはもっと理にかなっています。

ただし、請求書をモデル化しています。多くの理由から、請求書は特定の時点でのステータスを反映する必要があります。刻々と変化する在庫が請求書に属することはめったにありません。アイテムと請求書のデータをモデル化する方法は次のとおりです

{
  '_id':'12432',
  'name':'SuperFoo',
  'description':'Without SuperFoo, you can't bar or baz!',
  'current_price':49.99
 }

他の項目も同様です。

これで、請求書は非常にシンプルになります。

{ _id:"Invoice2",
  customerId:"987654"
  date:ISODate("2014-07-07T12:42:00Z"),
  delivery_address:"Foo Blvd 42, Appt 42, 424242 Bar, BAZ"
  items:
    [{id:'12432', qty: 2, price: 49.99},
     {id:'54352', qty: 1, price: 29.99}
    ]
}

請求書には、特定の時点でのみ有効である可能性があるもの (価格と配送先住所は変更される可能性があります) が保持され、在庫と請求書の両方を簡単に照会できます。

// How many items of 12432 are in stock?
db.products.find({_id:'12432'},{qty_in_stock:1})

// How many items of 12432 were sold during July and what was the average price?
db.invoices.aggregate([
  {$unwind:"$items"},
  {
    $match:{
      "items.id":"12432",
      "date":{
         $gt:ISODate("2014-07-01T00:00:00Z"),
         $lt:ISODate("2014-08-01T00:00:00Z")
      }
     }
   },
   {$group : { _id:"$items.id", count: { $sum:"$items.qty" }, avg:{$avg:"$items.price"} } }
])

// How many items of each product sold did I sell yesterday?
db.invoices.aggregate([
  {$match:{ date:{$gte:ISODate("2014-11-16T00:00:00Z"),$lt:ISODate("2014-11-17T00:00:00Z")}}},
  {$unwind:"$items"},
  {$group: { _id:"$items.id",count:{$sum:"$qty"}}}
])

各製品の在庫数に関するクエリと組み合わせると、何かを注文する必要があるかどうかがわかります (コードでその計算を行う必要がありますが、MongoDB でこれを行う簡単な方法はありません)。

「小さな」変更で、多くの質問に答えられることがわかります。

そして、それが基本的にどのように機能するかです。リレーショナル データでは、エンティティが適切に反映されるようにデータをモデル化してから、

このデータから答えを得るにはどうすればよいですか?

一般にNoSQL、特にMongoDBでは、最初に尋ねます

どの質問に答えてもらう必要がありますか?

それに応じてデータをモデル化します。微妙ですが、重要な違いです。

于 2014-11-17T10:08:47.120 に答える