【问题标题】:Mongoose pre.save() async middleware not working on record creationMongoose pre.save() 异步中间件无法创建记录
【发布时间】:2015-01-31 13:09:02
【问题描述】:

我正在使用 keystone@0.2.32。我想将帖子类别更改为树结构。下面的代码运行良好,但当我创建一个类别时,它进入了死锁:

var keystone = require('keystone'),
	Types = keystone.Field.Types;

/**
 * PostCategory Model
 * ==================
 */

var PostCategory = new keystone.List('PostCategory', {
	autokey: { from: 'name', path: 'key', unique: true }
});

PostCategory.add({
	name: { type: String, required: true },
	parent: { type: Types.Relationship, ref: 'PostCategory' },
	parentTree: { type: Types.Relationship, ref: 'PostCategory', many: true }
});

PostCategory.relationship({ ref: 'Post', path: 'categories' });

PostCategory.scanTree = function(item, obj, done) {
	if(item.parent){
		PostCategory.model.find().where('_id', item.parent).exec(function(err, cats) {
			if(cats.length){
				obj.parentTree.push(cats[0]);
				PostCategory.scanTree(cats[0], obj, done);
			}
		});
	}else{
		done();
	}
}

PostCategory.schema.pre('save', true, function (next, done) { //Parallel middleware, waiting done to be call
	if (this.isModified('parent')) {
        this.parentTree = [];
		if(this.parent != null){
			this.parentTree.push(this.parent);
			PostCategory.scanTree(this, this, done);
		}else
			process.nextTick(done);
    }else
		process.nextTick(done); //here is deadlock.

    next();
});

PostCategory.defaultColumns = 'name, parentTree';
PostCategory.register();

非常感谢。

【问题讨论】:

    标签: asynchronous mongoose middleware keystone


    【解决方案1】:

    我认为这是 keystone.js 的错误。我已更改 schemaPlugins.js 104 行

    来自

    this.schema.pre('save', function(next) {
    

    this.schema.pre('save', true, function(next, done) {
    

    并从第 124 行更改为以下内容,

    		// if has a value and is unmodified or fixed, don't update it
    		if ((!modified || autokey.fixed) && this.get(autokey.path)) {
    			process.nextTick(done);
    			return next();
    		}
    
    		var newKey = utils.slug(values.join(' ')) || this.id;
    
    		if (autokey.unique) {
    			r = getUniqueKey(this, newKey, done);
    			next();
    			return r;
    		} else {
    			this.set(autokey.path, newKey);
    			process.nextTick(done);
    			return next();
    		}

    它有效。

    【讨论】:

      【解决方案2】:

      正如我对您在此处登录 Keystone 的问题所解释的那样:https://github.com/keystonejs/keystone/issues/759

      这似乎是 mongoose 中一个可重现的错误,在以下情况下会阻止中间件解析:

      • 并行中间件运行执行查询,然后是
      • 执行查询的串行中间件运行

      将 Keystone 的 autokey 中间件更改为以并行模式运行可能会导致其他用例出现错误,因此无法完成。答案是以串行模式而不是并行模式实现您的 parentTree 中间件。

      另外,我注意到的其他一些事情:

      • 您的中间件中存在错误,其中第一个父项被添加到数组中两次。
      • scanTree 方法最好作为 schama 上的方法实现
      • 您可以使用findById 方法进行更简单的父查询

      架构方法如下所示:

      PostCategory.schema.methods.addParents = function(target, done) {
          if (this.parent) {
              PostCategory.model.findById(this.parent, function(err, parent) {
                  if (parent) {
                      target.parentTree.push(parent.id);
                      parent.addParents(target, done);
                  }
              });
          } else {
              done();
          }
      }
      

      而固定的中间件是这样的:

      PostCategory.schema.pre('save', function(done) {
          if (this.isModified('parent')) {
              this.parentTree = [];
              if (this.parent != null) {
                  PostCategory.scanTree(this, this, done);
              } else {
                  process.nextTick(done);
              }
          } else {
              process.nextTick(done);
          }
      });
      

      【讨论】:

        猜你喜欢
        • 2012-11-14
        • 2022-01-14
        • 1970-01-01
        • 1970-01-01
        • 2018-12-29
        • 2014-12-13
        • 1970-01-01
        • 1970-01-01
        • 2021-12-20
        相关资源
        最近更新 更多