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

问题是我显然想要一个项目itemId,这样我就可以获得每个项目的许多子文档......
一种解决方案可能是遍历所有order.items,但这不是最佳的,当然(order.items我可以很多......) . 查询时可能会出现同样的问题order.items...

问题是:如何在itemPerOrderSchema数组中插入项目而不必遍历订单中已插入的所有项目?

4

2 回答 2

2

首先,您可能需要将 orderId 添加到您的 itemPerOrderSchema,因为 orderId 和 itemId 的组合将使记录唯一。

假设 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
});

然后更新您的订单非常简单。假设您要向客户 123 添加 3 个编号为“xyz”的项目。

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

即使客户没有条目,也可以在此处传递 upsert 以创建订单。

这样做的缺点:

  • 如果您使用聚合框架,则无法迭代您的项目,或者如果您有一组有限的已知 itemId,那么非常冗长。你可以用 mapReduce 来解决这个问题,它可能会慢一点,这取决于你在那里有多少,所以 YMMB。

  • 您在客户端上没有干净的items阵列。您可以通过任一客户端提取此信息(简单let items = Object.keys(order.items).map(key => ({ key: order.items[key] }));或使用猫鼬虚拟字段或 schema.path() 来解决此问题,但这可能是另一个问题,已经回答了。

于 2016-01-10T20:30:01.080 回答