Как выполнить запрос изнутри предварительного запроса Mongoose в приложении Node.js/Express?

Я создаю базовый блог в Node.js/Express, используя MongoDB с Mongoose ORM.

У меня есть pre 'save' hook, который я бы хотел использовать для автоматического создания пула блога/идеи для меня. Это работает отлично и хорошо, за исключением той части, где я хочу выполнить запрос, чтобы увидеть, есть ли какие-либо другие существующие сообщения с тем же самым промахом, прежде чем продолжить.

Однако, похоже, что this не имеет доступа к .find или .findOne(), поэтому я продолжаю получать сообщение об ошибке.

Какой лучший способ приблизиться к этому?

  IdeaSchema.pre('save', function(next) {
    var idea = this;

    function generate_slug(text) {
      return text.toLowerCase().replace(/[^\w ]+/g,'').replace(/ +/g,'-').trim();
    };

    idea.slug = generate_slug(idea.title);

    // this has no method 'find'
    this.findOne({slug: idea.slug}, function(err, doc) {
      console.log(err);
      console.log(doc);
    });

    //console.log(idea);
    next();
  });

Ответ 1

К сожалению, он не задокументирован очень хорошо (не упоминается об этом в Документах Document.js API), но документы имеют доступ к их моделям через constructor поле - я использую его все время для регистрации вещей из плагинов, что дает мне доступ к той модели, к которой они привязаны.

module.exports = function readonly(schema, options) {
    schema.pre('save', function(next) {
        console.log(this.constructor.modelName + " is running the pre-save hook.");

        // some other code here ...

        next();
    });
});

В вашей ситуации вы должны уметь:

IdeaSchema.pre('save', function(next) {
    var idea = this;

    function generate_slug(text) {
        return text.toLowerCase().replace(/[^\w ]+/g,'').replace(/ +/g,'-').trim();
    };

    idea.slug = generate_slug(idea.title);

    // this now works
    this.constructor.findOne({slug: idea.slug}, function(err, doc) {
        console.log(err);
        console.log(doc);
        next(err, doc);
    });

    //console.log(idea);
});

Ответ 2

В this у вас есть документ, а не модель. Метод findOne отсутствует в документе.

Если вам нужна модель, вы всегда можете получить ее, как показано здесь. Но более умным было бы просто присвоить модель переменной в точке творения. Затем используйте эту переменную где угодно. Если он находится в другом файле, используйте module.exports и требуйте, чтобы его можно было найти в другом месте в вашем проекте. Что-то вроде этого:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/dbname', function (err) {
// if we failed to connect, abort
if (err) throw err;
var IdeaSchema = Schema({
    ...
});
var IdeaModel = mongoose.model('Idea', IdeaSchema);
IdeaSchema.pre('save', function(next) {
    var idea = this;

    function generate_slug(text) {
        return text.toLowerCase().replace(/[^\w ]+/g,'').replace(/ +/g,'-').trim();
    };

    idea.slug = generate_slug(idea.title);

    // this has no method 'find'
    IdeaModel.findOne({slug: idea.slug}, function(err, doc) {
        console.log(err);
        console.log(doc);
    });

    //console.log(idea);
    next();
   });
// we connected ok
})