使用 mongoose 钩子重试保存重复键错误
Posted
技术标签:
【中文标题】使用 mongoose 钩子重试保存重复键错误【英文标题】:Use mongoose hook to retry saving on duplicate key error 【发布时间】:2016-02-28 11:42:18 【问题描述】:我想使用 mongoose 中间件挂钩重新尝试保存文档,以防初始保存因重复键错误而失败。用例如下:
我的模型使用自动生成的 slug 进行识别。例如。 item
、item-2
、item-3
、……、item-n
。如果item
已经存在,则应将计数器添加到 slug。我无法提前检查“下一个”slug,因为我需要在任何情况下避免冲突。
由于这个逻辑会涉及到几个不同的模型,我想把它隔离成一个猫鼬插件。
这个想法可能吗?例如。 schema.post('save', handler)
仅在成功保存时执行。还有其他可以利用的钩子吗?
【问题讨论】:
【参考方案1】:我正在使用 pre save hook 来检查 slug 是否已经存在,并使用以下代码,到目前为止它似乎工作得很好。
pageSchema.pre('save', function(next)
var page = this;
page.createdDT = new Date();
page.updatedDT = new Date();
page.slug = page.title.slug(); // create slug from title
var re = new RegExp(page.slug, 'i');
mongoose.models["page"].find(slug: $regex: re, function(err, pages)
// slug doesn't exist, good to go
if(!err && !pages) return next();
var slugs = [];
// let's get all slugs
pages.forEach(function(page)
slugs.push(page.slug);
);
// keep increasing `i` until slug is unique
// set i to 1 to avoid hello-0
var i = 1;
var tempSlug = page.slug;
while(slugs.indexOf(tempSlug) >= 0)
tempSlug = page.slug + '-' + i;
i++;
//unique slug for example "hello-2"
page.slug = tempSlug;
next();
);
);
【讨论】:
感谢您的建议。我在使用此解决方案时遇到的潜在问题是,检查可用的 slug 并保存新文档不是原子的。老实说,目前这不是一个巨大的问题,但我想从一开始就避免未来的陷阱。【参考方案2】:我最终选择了mongoose-uniqueslugs
使用的解决方案,我根据我们的需要进行了调整。虽然此变体不仅适用于 pre/post 挂钩,但它确保了原子性(即不提前检查可用的 slug 然后保存,而只是重新尝试)。
中心思想是覆盖模型的 save
函数(参见 enhanceModel
函数)并提供一个包装器,它通过 slug 碰撞捕获独特的错误,然后重新尝试保存(而不是附加的随机字符串,我们想要对于序列号方法)。
【讨论】:
以上是关于使用 mongoose 钩子重试保存重复键错误的主要内容,如果未能解决你的问题,请参考以下文章