2016-07-26 74 views
0

我为我的项目中的某些模型实施了slug,我想保持它的唯一性和基于文档的数据。猫鼬独特的自动增量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”)重新保存文档。 。

+1

在保存中处理此错误可能会产生问题。您已经离开预处理程序。你可以创建另一个集合'users-slug'并尝试将slug插入到那里(slug字段也应该是唯一的)。你可以在预存储中完成。如果你在那里失败了,你可以改变slu and并重试。 –

回答

0

好的,所以我最终有一个单独的slu model模型,就像@AmiramKorach建议的那样。然后我实现了一个获取slu module的模块,它依赖于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' ] 
}); 
1

我知道这个问题是一岁了,但我有同样的问题,来到直到第一个免费的金属块发现,不需要客户端重试的解决方案。如果您有第二个集合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); 

您提供全塞那将是john.doe,再john.doe.2等结束了。

这种方法要快得多,因为它找到一个带有一个查询的slu g。我没有使用猫鼬,因为这是这个收藏必须做的唯一的事情,而且看起来过于夸张。

编辑:请记住你的客户应该确认generatedSlug还没有以点号和数字结尾,那么你会遇到问题。