如何在Node.js/Express应用程序中的Mongoose预钩子中查询?

25

我正在使用MongoDB w/ Mongoose ORM在Node.js / Express中构建一个基本的博客。

我有一个预先的“save”挂钩,我想用它来自动生成一个博客/想法的slug。这部分工作得很好,但是如果在继续之前要查询是否存在具有相同slug的其他帖子,则会出现问题。

然而,看起来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();
  });
2个回答

63

不幸的是,它的文档并不是非常完整(在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
请注意,如果您要修改文档或根据findOne()的结果抛出错误或其他操作,则需要将next()回调移动到findOne回调函数内部。 - ccnokes
9
你是如何学会这个的?真棒,一定要记录下来...... - salihcenap
我们可以在findOne回调方法内使用.save()函数吗? 在哪些查询内部可以使用.save()函数? - Maulik Soneji
1
这就是为什么有时我更倾向于在 Stackoverflow 上寻求帮助,而不是查看文档。有些文档实在太令人沮丧了。如果没有 Stackoverflow,我又怎么能知道呢? - Fortune

2
在这里,你得到的是文档而不是模型。文档上没有findOne方法。
如果你需要模型,你可以像这里所示一样获取它。但更明智的做法是在创建时将模型分配给一个变量。 然后在任何需要的地方使用这个变量。如果它在另一个文件中,则使用module.exports和require来在项目中的任何其他地方获取它。 像这样:
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
})

所以基本上,在 pre-hook 中不要执行查询以查找可能的重复项。在 save() 之前执行查询。 - doremi
不,你可以随时在模型上调用查询方法。让我编辑我的答案以添加代码。 - Capaj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接