2016-07-26 38 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還沒有以點號和數字結尾,那麼你會遇到問題。