我正在为项目中的某些模型实施slug
,并且我希望根据文档的数据保持其唯一性。
var user = new User({ name: { first: 'John', last: 'Doe' });
user.save().then(function(user) {}); // user.slug === 'john-doe'
var user2 = new User({ name: { first: 'John', last: 'Doe' });
user2.save().then(function(user) {}); // user.slug === 'john-doe-2'
我可以成功实现它,我甚至可以在.pre('save')
钩子上查询数据库,如下所示:
UserSchema.pre('save', function(next) {
var user = this;
return User.distinct('slug')
.exec()
.then(function(slugs) {
// generate a unique slug like "john-doe-2",
// checking it against slugs that are already
// in the database, and set it to user
next();
});
});
唯一的问题是并发请求(不太可能,但仍然可能):
var user = new User({ name: { first: 'John', last: 'Doe' }),
user2 = new User({ name: { first: 'John', last: 'Doe' });
Promise.all([ user.save(), user2.save() ]);
// throws validation error if slug should be unique
为此,我正在寻找能够处理验证错误(唯一索引重复)的解决方案,并尝试使用更新的参数重新保存文档(例如" john-doe-2&#34 ;)
答案 0 :(得分:1)
我知道这个问题现在已经有一年了,但是我遇到了同样的问题并找到了一个解决方案,在找到第一个免费slug之前不需要客户端重试。如果您有第二个集合userslugs
,请执行
var generatedSlug = 'john.doe';
var count = db.accountslugs.findOneAndUpdate({
_id: generatedSlug
}, {
$inc: { count: 1 }
}, {
upsert: true,
returnNewDocument: true
}).count;
var fullSlug = generatedSlug + ((count === 1) ? "" : "." + count);
你最终得到一个完整的slug,首先是john.doe
,然后是john.doe.2
,依此类推。
这种方法要快得多,因为它找到一个带有一个查询的slug。我没有使用猫鼬,因为这是这个集合必须做的唯一的事情,它似乎有点过分。
修改:请记住,您的客户应该验证generatedSlug
是否已经以点后跟数字结尾,那么您将遇到问题。
答案 1 :(得分:0)
好的,所以我最终得到了一个单独的slugs模型,有点像@AmiramKorach建议的那样。然后我实现了一个模块来获取一个slug,它依赖于Mongo的11000错误(重复条目)。
function getSlug(base, counter) {
if (typeof counter === 'undefined') counter = 0;
var url = base;
if (counter > 0) url += '-' + counter;
var slug = new Slug({ url: url });
return slug.save()
.then(function(slug) {
return slug.url;
})
.catch(function(reason) {
if (reason.code === 11000) return getSlug(base, counter + 1);
throw reason;
});
}
Promise.all([
getSlug('john-doe'),
getSlug('john-doe'),
getSlug('john-doe'),
getSlug('john-doe'),
getSlug('john-doe'),
getSlug('john-doe'),
getSlug('john-doe')
])
.then(function(slugs) {
// slugs are [ 'john-doe', 'john-doe-1', 'john-doe-2',
//'john-doe-4', 'john-doe-5', 'john-doe-6', 'john-doe-3' ]
});