【问题标题】:Mongoose - Efficient update on an indexed array of mongoose.Schema.Types.MixedMongoose - 对 mongoose.Schema.Types.Mixed 索引数组的有效更新
【发布时间】:2016-01-26 08:50:56
【问题描述】:

我有以下简化方案:

var restsSchema = new Schema({
    name: String
    menu: [mongoose.Schema.Types.Mixed]
});

我的文档可能如下所示:

{
     name: "Sandwiches & More",
     menu: [
                {id:1,name:"Tona Sandwich",price: 10, soldCounter:0},
                {id:2,name:"Salami Sandwich",price: 10, soldCounter:0},
                {id:3,name:"Cheese Sandwich",price: 10, soldCounter:0}
     ]
}

集合rests 的索引为:

db.rests.createIndex( { "menu.id": 1} , { unique: true })

假设我有这个 id 数组 [1,3],基于此我需要将 soldCounter 增加 1 个 menu ids=1 或 3 的项目。

什么是必须有效的方法?

感谢帮助!

编辑: 我使用了以下解决方案:

db.model('rests').update({ _id: restid,'menu.id': {$in: ids}}, {$inc: {'menu.$.soldCounter': 1}}, {multi: true},function(err) {
        if(err)
            console.log("Error while updating sold counters: " + err.message);
    });

其中ids 是具有菜单项ID 的整数数组。 restid 是我们要在集合中编辑的特定文档的 id。

由于某种原因,只有 ids 数组中的第一个 id 正在更新。

【问题讨论】:

  • 您是否已经实现了一些您认为不够高效的东西?
  • 是的,我更新了整个剩余模型,它在其未简化的形式中相当大。我使用find() 找到了其余部分,在回调中我在循环中寻找想要的 soldCounters,增加它们并保存模型。效率不高,还可能导致一些数据完整性问题。

标签: node.js mongodb mongoose


【解决方案1】:

有一种方法可以进行多次更新,这里是: 只需确保数组中有要更新的索引即可。

var update = { $inc: {} };
for (var i = 0; i < indexes.length; ++i) {
  update.$inc[`menu.${indexes[i]}.soldCounter`] = 1;
}
Rests.update({ _id: restid }, update, function(error) {
  // ...
});

【讨论】:

  • 当然可以,但是您需要事先准备好索引。您必须绝对确定该数组不会被修改,否则您将遇到数据完整性问题。
  • 如果你是一个优秀的程序员,那么你总是知道索引完全不关心数组是否被改变。这完全取决于您是否正确准备了数据。
  • 如果在计算索引和应用更新之间,数据被另一个请求修改,由分布式系统的另一个服务器处理,该怎么办?不管你是多么优秀的程序员。
  • 这在我的测试用例中是不可能的,但你是绝对正确的。想要使用此解决方案的人需要确保他不会遇到任何数据完整性问题。
【解决方案2】:

似乎不可能一次更新多个子文档(请参阅this answer)。所以查找和保存似乎是唯一的解决方案。

Rest.findById(restId).then(function(rest){
  var menus = rest.menu.filter(function(x){
    return menuIds.indexOf(x.id) != -1;
  });
  for (var menu of menus){
    menu.soldCounter++;
  }
  rest.save();
});

最后只有一个查找和一个保存请求。

【讨论】:

  • 这是一个不错的解决方案,但如果我只有 restid 而不是整个模型怎么办?是否仍然可以使用您的解决方案,只需稍加改动即可包含restid
  • 没关系,我知道了 :) db.model('rests').update({ _id: restid,'menu.id': {$in: ids}}, {$inc: {'menu.$.soldCounter': 1}}, {multi: true}) 感谢您的帮助!
  • 由于某种原因,唯一正在更新的soldCounter 是给定数组中的第一个id。知道为什么吗?我已更新我的问题以包含我的发现
  • 请看我的回答
猜你喜欢
  • 2019-03-25
  • 1970-01-01
  • 2013-03-19
  • 2020-09-13
  • 2021-12-22
  • 2012-12-20
  • 2019-12-15
  • 1970-01-01
相关资源
最近更新 更多