1

注文と注文ごとのアイテムを処理するために、MEAN プロジェクトでサブドキュメントを使用しています。

これらは私の(簡略化された)スキーマです:

var itemPerOrderSchema = new mongoose.Schema({
  itemId: String,
  count: Number
});
var OrderSchema = new mongoose.Schema({
  customerId: String,
  date: String,
  items: [ itemPerOrderSchema ]
});

itemPerOrderSchema 配列にアイテムを挿入するには、現在行っています。

var orderId = '123';
var item = { itemId: 'xyz', itemsCount: 7 };
Order.findOne({ id: orderId }, function(err, order) {
  order.items.push(item);
  order.save();
});

問題は、明らかに ごとに 1 つのアイテムが必要itemIdであり、この方法でアイテムごとに多くのサブドキュメントを取得することです...
1 つの解決策は、 all をループすることorder.itemsですが、もちろんこれは最適ではありませorder.itemsん(多くの可能性があります...) . クエリを実行するときに同じ問題が発生する可能性がありorder.itemsます...

itemPerOrderSchema問題は、注文に既に挿入されているすべてのアイテムをループすることなく、配列にアイテムを挿入するにはどうすればよいかということです。

4

2 に答える 2

2

まず、orderId と itemId の組み合わせによってレコードが一意になるため、おそらく itemPerOrderSchema に orderId を追加する必要があります。

orderId が itemPerOrderSchema に追加されていると仮定すると、次の実装をお勧めします。

function addItemToOrder(orderId, newItem, callback) {
  Order.findOne({ id: orderId }, function(err, order) {
    if (err) {
        return callback(err);
    }

    ItemPerOrder.findOne({ orderId: orderId, itemId: newItem.itemId }, function(err, existingItem) {
      if (err) {
        return callback(err);
      }

      if (!existingItem) {
        // there is no such item for this order yet, adding a new one
        order.items.push(newItem);
        order.save(function(err) {
          return callback(err);
        });
      }

      // there is already item with itemId for this order, updating itemsCount
      itemPerOrder.update(
        { id: existingItem.id }, 
        { $inc: { itemsCount: newItem.itemsCount }}, function(err) {
            return callback(err);
        }
      );
    });   
  });
}

addItemToOrder('123', { itemId: ‘1’, itemsCount: 7 }, function(err) {
    if (err) {
    console.log("Error", err);
  }
  console.log("Item successfully added to order");
});

これが役立つことを願っています。

于 2016-01-10T17:36:44.093 に答える
2

アイテムに配列の代わりにオブジェクトを使用できる場合は、単一クエリの更新用にスキーマを少し変更できるかもしれません。

このようなもの:

{
  customerId: 123,
  items: {
     xyz: 14,
     ds2: 7
  }
}

したがって、各 itemId はオブジェクトのキーであり、配列の要素ではありません。

let OrderSchema = new mongoose.Schema({
  customerId: String,
  date: String,
  items: mongoose.Schema.Types.Mixed
});

その後、注文の更新は非常に簡単です。顧客番号 'xyz' の 3 つのアイテムを顧客 123 に追加するとします。

db.orders.update({
  customerId: 123
},
{
  $inc: {
    'items.xyz': 3
  }
}, 
{
  upsert: true
});

顧客がエントリを持っていなくても、ここで upsert を渡して注文を作成します。

これの欠点:

  • 集約フレームワークを使用している場合、アイテムを反復処理することが不可能であるか、制限された既知のアイテム ID のセットがある場合は非常に冗長です。これは mapReduce で解決できますが、そこにあるマップの数によっては少し遅くなる可能性があるため、YMMB.

  • itemsクライアントにクリーンなアレイがありません。クライアントがこの情報を抽出することで修正できます(単純なlet items = Object.keys(order.items).map(key => ({ key: order.items[key] }));もの、またはマングース仮想フィールドまたはschema.path()を使用しますが、これはおそらく別の質問であり、すでに回答されています。

于 2016-01-10T20:30:01.080 に答える