在node.js / Mongoose项目中,我有一个包含对外部图像文件的引用的模式。
var PageSchema = new Schema({
title: String
, media: {
digest: String
, name: String
}
});
这些文件具有存储在文件本身中的其他属性:url,width,height,exif字段等。在将模型发送到res.render()之前,需要填充这些字段。
对于某些领域,事情是同步的,虚拟只是完成工作:
PageSchema.virtual('media.url').get(function () {
return appPaths.fileUrl(this.media);
});
但是,宽度/高度或exif字段需要异步调用。我想过使用中间件来填充它们,但这似乎不起作用:
PageSchema.post('init', function(next) {
var media = this.media;
var fileName = filedb.absoluteFilePath(media);
im.identify(fileName, function(err, features) {
if (err) {
media.width = 0;
media.height = 0;
} else {
media.width = features.width;
media.height = features.height;
}
next();
});
});
我做错了什么?是否有解决此类问题的通用设计模式? (除了在数据库本身中复制这些信息外?)
答案 0 :(得分:5)
真正的问题是,mongoose目前似乎有一个不稳定的post
回调实现。虽然pre('init',function(next){ ... });
按预期工作,但post('init',function(next){ ... });
实际上并没有通过next
函数。实际上,post init
回调函数在调用时不会收到任何参数。
因此,我经常为查询回调编写一个包装器来制作一种DIY中间件:
var setAsyncVirtuals = function(callback){
return function(err, docs){
if(err) return callback(err);
var i = done = docs.length;
if(i > 0)
while(i--){
(function(i){
var filename = getFilename();
im.identify(filename, function(err, features) {
if (err) {
docs[i].media.width = 0;
docs[i].media.height = 0;
} else {
docs[i].media.width = features.width;
docs[i].media.height = features.height;
}
done--;
if(done <= 0) callback(null, docs);
});
})(i); // bind i to hold value for async call
}
else callback(null, docs);
}
}
然后
Page.find({}, setAsyncVirtuals(function(err,docs){
res.send(docs); // these have media.width & media.height assigned
}));