【问题标题】:mongoose pre validate hook not firing猫鼬预验证钩子没有触发
【发布时间】:2017-03-08 05:20:55
【问题描述】:

我正在尝试创建一个模型,然后创建另一个模型并使用 mongoose 保存对原始模型的引用。我一直在查看 mongoose 关于中间件及其钩子的文档,但其中一些似乎没有触发。

这个答案告诉我为什么我的初始化钩子不会触发 HEREprepost init 只有在从数据库加载预先存在的模型时才会触发。所以我读到validate 将在创建新模型时运行。知道我从preinit切换到prevalidate

这是我正在尝试做的代码:

GroupSchema.pre('validate', function (next, data) {
    console.log("inside pre validate");
    if (data.location) {
        location = new Location(data.location);
        data.location = location._id;
        location.save(function (err) {
            if (err) handleError(err);
        });
    }

    next();
})

我知道我不能使用this,因为该文档还没有填充数据。所以这就是为什么我有data,但这似乎仍然不起作用,哦,我得到了我应该从这个answer 传递的参数。

任何帮助将不胜感激。

**************更新**************

为了增加清晰度,使用答案中推荐的内容并将我的 pre validate 函数更改为:

GroupSchema.pre('validate', function (next, data) {
    console.log("inside pre validate", this);
    if (this.location) {
        location = new Location(this.location);
        this.location = location._id;
        location.save(function (err) {
            if (err) handleError(err);
        });
    }

    next();
})

我收到以下错误

service err: CastError: Cast to ObjectId failed for value "[object Object]" at path "location"

这是有道理的,因为在我的模型中,它需要 ObjectId 而不是 [object, Object],这是我要传递的。但是,我认为我可以保存location,获取生成的ObjectId 并将其存储在组模型中,然后再引发错误。因此,最初使用 pre init 直到发现不起作用,现在发现 pre validate 也不起作用。有什么办法可以做我正在尝试的事情吗?

这是我正在尝试的顺序:

  1. 创建位置
  2. 获取新的ObjectId
  3. 将新位置 ObjectId 存储在组中,而不是对象本身

我试图将其添加到 pre 挂钩的原因是,我可以将这段代码放在一个位置,并且在更新组模型时它会自动处理这个问题。

【问题讨论】:

  • location: [{ type: ObjectId, ref: 'Location' }], 这是对另一个集合的引用
  • 嗯...它是一个数组与您将data.location 传递给new Location 调用然后使用data.location = location._id; 分配它的代码并不匹配。
  • 我明白你在说什么,我正在把应该是一个数组的东西变成一个变量。但是,这不是我遇到的问题。 pre validate 根本没有被解雇。因此,如果这是一个问题,它就不会出现,因为它甚至还没有达到这一点。
  • 其实我觉得正好相反。因为location 不是正确的类型,所以验证在进行自定义验证之前就失败了。
  • prevalidate 在模型实际验证之前不会触发吗?

标签: mongoose


【解决方案1】:

您尝试做的事情不适合 validate 或任何其他中间件,因为您需要提供位置数据以及创建组本身所需的内容。

更合适的方法是在 GroupSchema 上创建一个静态方法,显式执行此增强的创建功能。

所以假设基本位置和组模式如下:

var LocationSchema = new Schema({
    city: String,
    state: String
});

var GroupSchema = new Schema({
    name: String,
    location: {type: ObjectId, ref: 'Location'}
});

向组模式添加静态方法并注册模型:

GroupSchema.statics.createWithLocation = function(group, location, callback) {
    Location.create(location, function(err, location) {
        if (err) return callback(err);
        group.location = location._id;
        Group.create(group, callback);
    });
};

var Location = mongoose.model('Location', LocationSchema);
var Group = mongoose.model('Group', GroupSchema);

通过分别传递组和位置数据参数来调用新方法:

Group.createWithLocation(
    {name: 'group1'}, 
    {city: 'New York', state: 'NY'},
    function(err, group) {
        console.log('group created with location: ', group);
    }
);

【讨论】:

  • 我同意,使用中间件我不能做我想做的事。
【解决方案2】:

pre(validate) 在“.save”之前触发,并注意数据没有当前文档。“this”变量将拥有它。还请注意,只要我们执行“.save”,.pre(validate) 就会触发“。下面是一个如何做你正在寻找的东西的例子。我解决了它,它工作得很好。

   var mongoose = require('mongoose');
    var Schema = mongoose.Schema;
    //group schema
    var GroupSchema = new Schema({
        location: String,
        pass: String
    });
    //dependant location schema
    var LocationSchema = new Schema({
        city: String
    });

  //here I compile it into a model -groupschema
    var Groupuser = mongoose.model('usertest', GroupSchema, 'usertest');
    //here I compile it into a model-location schema
    var Location = mongoose.model('locationtest', LocationSchema, 'locationtest');


    //here is the pre validate,note this will trigger when we save groupschema realted documents.

    GroupSchema.pre('validate', function(next, data) { //will be triggered before the save
        console.log("inside pre validate", this); //the this will have amsterdam,and test see below.
        if (this.location) {//will be amsterdam
            var location = new Location();
            location.city = this.location//adding amsterdam to the location.city 
            location.save(function(err, data) {//this data will have the location document that we just saved.
            });
        }
        next();
    });

    //now I create a new user for groupschema
    var newuser = new Groupuser();
    newuser.location = 'amsterdam';
    newuser.pass = 'test'
    newuser.save(function(err) { //Before this save function does the save,it triggers the .pre(validatE)
        if (err) return console.log(err);//
    });

我可能没有按照您的要求确定内部位置功能,但我确信 .pre(validate) 仅在您执行 .save 时触发。 它可以是新文档或现有文档。另请注意,它不会在加载模型时触发。

1)we define a schema (var schema=new Schma({datatypes})
2)we compile it into a model(var model=mongoose.model('collectionname',schema)
3)we instantiate a new variable of the model(var user=new model(); and then define the values
4) finally we save the data(user.save()->its here that the pre.validate triggers
Hope its clear now

【讨论】:

  • 我已经用更多信息编辑了我的答案。希望你明白我想说什么,我希望这就是你要找的。​​span>
  • 感谢您的回答,这是我现在遇到的错误。 service err: CastError: Cast to ObjectId failed for value "[object Object]" at path "location" 我明白它为什么这样做,这就是我希望我能在它抛出错误之前抓住的。它需要ObjectId 而不是[object, object],这就是为什么我最初想看看我是否可以使用pre init 希望我可以保存位置并设置新的ObjectId,以免它对我生气。这有意义吗?
【解决方案3】:

您的问题很可能是在 实际保存位置后调用了 next() next(),因为它被异步调用。

如果您将next() 添加到save() 内部,我相信您应该解决您的问题。

GroupSchema.pre('validate', function (next, data) {
  console.log("inside pre validate", this);
  if (this.location) {
    location = new Location(this.location);
    this.location = location._id;
    location.save(function (err) {
        if (err) handleError(err);
        next();
    });
  } else {
    next();
  }
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 2015-10-08
    • 2023-03-15
    • 2012-08-08
    • 2018-06-09
    • 2016-09-23
    • 1970-01-01
    相关资源
    最近更新 更多