2011-11-15 69 views
3

在node.js/Mongoose項目中,我有一個包含對外部圖像文件的引用的模式。使用貓鼬中間件來添加異步虛擬

var PageSchema = new Schema({ 
    title: String 
    , media: { 
     digest: String 
     , name: String 
    } 
}); 

這些文件具有被存儲在文件本身在附加屬性:URL,寬度,高度,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(); 
    }); 
}); 

我在做什麼錯?是否有解決這類問題的通用設計模式? (除了在數據庫本身中複製這些信息?)

回答

5

這裏真正的問題是,貓鼬目前似乎有一個不可思議的執行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 
}));