Asynchronous Mongoose pre.save()异步中间件无法创建记录

Asynchronous Mongoose pre.save()异步中间件无法创建记录,asynchronous,mongoose,middleware,keystone,Asynchronous,Mongoose,Middleware,Keystone,我正在使用keystone@0.2.32. 我想把帖子类别改成树状结构。以下代码运行良好,但在创建类别时,它会陷入死锁: var keystone=require('keystone'), 类型=keystone.Field.Types; /** *后分类模型 * ================== */ var PostCategory=new keystone.List('PostCategory'{ 自动键:{from:'name',path:'key',unique:true} }

我正在使用keystone@0.2.32. 我想把帖子类别改成树状结构。以下代码运行良好,但在创建类别时,它会陷入死锁:

var keystone=require('keystone'),
类型=keystone.Field.Types;
/**
*后分类模型
* ==================
*/
var PostCategory=new keystone.List('PostCategory'{
自动键:{from:'name',path:'key',unique:true}
});
PostCategory.add({
名称:{type:String,必需:true},
父项:{type:Types.Relationship,ref:'PostCategory'},
父树:{type:Types.Relationship,ref:'PostCategory',many:true}
});
关系({ref:'Post',path:'categories'});
PostCategory.scanTree=功能(项目、目标、完成){
如果(项.父项){
PostCategory.model.find().where(''u id',item.parent).exec(函数(err,cats){
如果(猫的长度){
对象parentTree.push(cats[0]);
后分类。扫描树(猫[0],obj,完成);
}
});
}否则{
完成();
}
}
PostCategory.schema.pre('save',true,function(next,done){//并行中间件,等待调用done
if(this.isModified('parent')){
this.parentTree=[];
如果(this.parent!=null){
this.parentTree.push(this.parent);
后分类。扫描树(这个,这个,完成);
}否则
过程。下一步(完成);
}否则
process.nextTick(done);//这里是死锁。
next();
});
PostCategory.defaultColumns='name,parentTree';

PostCategory.register()我认为这是keystone.js的一个bug。我已经更改了schemaPlugins.js 104行

并将第124行更改为以下内容:

//如果有值且未修改或固定,则不要更新它
if(!modified | | autokey.fixed)和&this.get(autokey.path)){
过程。下一步(完成);
返回next();
}
var newKey=utils.slug(values.join(“”))| | this.id;
if(autokey.unique){
r=getUniqueKey(这个,newKey,done);
next();
返回r;
}否则{
此.set(autokey.path,newKey);
过程。下一步(完成);
返回next();

}
正如我在这里解释的您登录Keystone的问题:

这似乎是mongoose中的一个可复制错误,它在以下情况下阻止中间件解决:

  • 并行中间件执行查询,然后执行
  • 执行查询的串行中间件运行
更改Keystone的
autokey
中间件以并行模式运行可能会在其他用例中导致错误,因此无法完成。答案是以串行模式而不是并行模式实现parentTree中间件

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

  • 中间件中有一个bug,第一个父级被添加到数组中两次
  • 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);
    }
});
固定中间件如下所示:

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);
    }
});