在mongoose schema.pre。上生成一个独特的slug(' update')

时间:2017-04-07 19:46:13

标签: javascript node.js mongodb mongoose

我想在mongoose中调用更新时生成一个slug,现在我有了这个并且它可以工作。

schema.pre('update', function (next) {
    const title = this._update.$set['title']
    this._update.$set['slug'] = slugify(title.toLowerCase())
    next()
})

问题是 slug unique:true 字段,所以如果添加两个标题相同的帖子,我会收到错误,例如:

"slug: post-2\" already exists."

所以现在在调用 next()之前我想确定我的slug是否已经存在调用find,现在我有了这个代码:

.pre('update', function (next) {
    const title = this._update.$set['title']
    this._update.$set['slug'] = slugify(title.toLowerCase())

    this._find({ slug }, function (err, docs) {
        if (err)
            console.log(err)
        else
            console.log(docs)
        next()
    })
})

但是当被调用时,我收到以下错误:

          ? callback(null, docs)
            ^

TypeError: callback is not a function

我该如何继续?

3 个答案:

答案 0 :(得分:0)

尝试这样的事情

// uniq slug generator function, converts `text` to `text1` if `text` exists 
schema.statics.generateSlug = function(text, suffix, callback){
    var _this = this;
    var possibleText = text + (suffix || '');
    _this.findOne({
        slug: slugify(possibleText.toLowerCase())
    }, function(err, item){
        if(!err) {
            if(!item) {
                callback(possibleText);
            } else {
                return _this.generateSlug(text, (suffix || 0) + 1, callback);
            }
        } else {
            callback(null);
        }
    });
};

schema.pre('update', function (next) {
    var _this = this;
    const title = _this._update.$set['title'];
    _this.generateSlug(title, null, function(possibleSlug) {
        if (possibleSlug) {
             _this._update.$set['slug'] = possibleSlug;
             next();
        } else return next(new Error('No possible slug'));

    });
})

答案 1 :(得分:0)

这是我的解决方案,如果没有必要,可以避免更换slu

Post.statics.slugify = function (next) {
    const title = this._update.$set['title']
    const _id = this._conditions['_id']

    const that = this
    this.model.slugify(title, _id, null, slug => {
        that._update.$set['slug'] = slug
        next()
    })
}

Post.pre('validate', function (text, _id, suffix, cb) {
    const field = text + (suffix || '')
    const slug = Slugify(field.toLowerCase())

    const that = this
    that.findOne({ slug }, (err, item) => {
        if (!err) {
            if (item)
                // Checks if current document has already the currect slug
                if (`${ item._id }` === `${ _id }`)
                    cb(slug)
                else
                    return that.slugify(`${ text }`, _id, (suffix || 0) + 1, cb)
            else
                cb(slug)
        }
        else
            cb(null)
    })
})

答案 2 :(得分:0)

如果没有使用async / await进行回调,代码看起来会更好:

schema.pre('update', async function() {
    //...
    let doc = await this.model.findOne({/* some filter */});
    //...
    this.update({}, { $set:{ slug } });
});

还应考虑没有_id,否则更新会影响多个文档。 也可以使用upsert选项创建新文档。

我建议使用一些existing solution

var mongoose = require('mongoose'),
    slug = require('mongoose-slug-updater'),
    mongoose.plugin(slug),
    Schema = mongoose.Schema,
    schema = new Schema({
        title: String,
        slug: { type: String, slug: "title", unique: true }
});