下面的我的代码包含架构和用于操作架构的name属性的pre('update')中间件。实际上我只想在name Collection中添加一个后缀,如果该值已存在于Item Collection中。
const ItemSchema = mongoose.Schema({
...
name : {type : String, required : true, unique : true, trim : true},
...
})
ItemSchema.pre("update", async function() {
let name = this.getUpdate().$set.name;
if (!name) return Promise.resolve();
let count = await ItemModel.find({name}).count().exec();
if(count>0) name = name + "_SOME_SUFFIX_BY_SOME_LOGIC";
this.getUpdate().$set.name = name;
});
ItemSchema.plugin(require('mongoose-unique-validator'));
const ItemModel = mongoose.model('Item', ItemSchema);
module.exports = ItemModel;
当我尝试更新/修补name属性时,计数似乎正确获取数字1并通过后缀更新名称。之后,我正确地使用正确操作的名称更新更新对象中的名称(因此带有后缀的名称确实不存在于集合中)
但是现在,当我尝试更新时,我收到以下错误:
验证失败:名称:错误,预期
name
是唯一的。值: `[名称] _SOME_SUFFIX_BY_SOME_LOGIC'
所以它告诉我,新的后缀名已经存在于数据库中,即使它没有。
(我在数据库中查找了后缀名,但我可以保证它不存在,因为我在测试集上运行它,但是还没有很多条目)
节点版本:8.1.1 mongoose版本:5.1.3 system:ubuntu 16.04
答案 0 :(得分:0)
我实际上发现,mongoose-unique-validator就是问题所在。我在一个描述原因的猫鼬问题中找到了一条评论。
因为mongoose-unique-validator依赖于异步操作,例如 .count()来验证数据库中是否存在文档 可能两个.count()调用大致同时执行, 两者都返回0,然后都插入到MongoDB中。你需要这样做 一般锁定操作使其在一般情况下正常工作。
解决此问题的唯一方法是仅使用一个进程并设置 你的mongodb连接池大小为1,但这限制了数量 您可以运行的应用服务器,只有mongodb保留才能使用 它基于每个连接阻止操作的遗留行为。