Mongodb Docpad:通过mongoose回调使用extendTemplateData

Mongodb Docpad:通过mongoose回调使用extendTemplateData,mongodb,mongoose,docpad,Mongodb,Mongoose,Docpad,我正在尝试构建一个简单的插件,将Mongo中的数据导入一个对象,在渲染时可以在该对象上进行迭代。完整的代码在我的中,但其本质是模拟feedr示例的失败尝试。我知道mongoose的东西在控制台日志工作的同时也在工作,但是将内容发送到docpad对象却让我大吃一惊 class mongoPlugin extends BasePlugin name: 'mongo' # Fetch list of Gigs getGigsData: (opts) ->

我正在尝试构建一个简单的插件,将Mongo中的数据导入一个对象,在渲染时可以在该对象上进行迭代。完整的代码在我的中,但其本质是模拟feedr示例的失败尝试。我知道mongoose的东西在控制台日志工作的同时也在工作,但是将内容发送到docpad对象却让我大吃一惊

class mongoPlugin extends BasePlugin
    name: 'mongo'

    # Fetch list of Gigs
    getGigsData: (opts) ->
        mongoose.connect ('mongodb://localhost/test')
        db = mongoose.connection;
        db.on 'error', console.error.bind(console, 'connection error:')
        db.once 'open', () -> 
            gigsSchema = mongoose.Schema {
                date : String,
                location : String
            }

            Gigs = mongoose.model 'Gigs', gigsSchema

            Gigs.find {}, (err, gigs) ->
                mongoose.connection.close()
                if err then console.error "db error"
                else 
                    console.dir gigs
                    opts["getGigsData"] = gigs
                    opts.templateData["getGigsData"] = gigs
                    return gigs

    extendTemplateData: (opts) ->
        opts.templateData["getGigsData"] = @getGigsData()
使用节点检查器并通过编辑docpad.coffee触发重新生成,我可以看到opts有一个字段templateData,但它是空的,并且与docpad.templateData非常不同,因此我在插件中选择了错误的对象。我可以看到其他人在{}中使用了一个名字,但我不知道这是怎么回事


完成插件代码后,我看到我的数据库数据成为承诺的参数,因此,也许这就是它应该与docpad.config.templateData重新集成的地方,但在实践中似乎不会发生这种情况

,因此这里的主要问题是,我们有一个异步函数
getGetsData
在同步函数(模板引擎)中执行。这很简单,是不可能的,因为模板引擎将继续并完成它的工作,而同步工作将在后台进行。这只是一般情况下编写node.js/asynchronous代码的一个问题

解决这个问题相当容易

  • opts.templateData[“getGigsData”]=@getGigsData()
    调用
    getGigsData
    ,而不传递
    opts
    ,因此当
    getGigsData
    尝试并使用opts时,它无法调用,因此会引发错误。解决方法是执行
    @getGigsData(opts)

  • opts.templateData[“getGigsData”]=@getGigsData(opts)
    @getGigsData(opts)
    的返回值分配给模板数据,但是,这一操作的结果是
    db.once
    调用的结果,因为这将在该范围内返回。当您执行
    返回gigs
    时,这实际上是
    gigs.find
    调用上
    (err,gigs)->
    回调的返回值,而不是
    getGigsData
    的返回值。这都是关于范围的

  • 由于数据库是异步的,我们需要使
    getGigsData
    异步。为此,我们将
    extendedtemplatedata:(opts)->
    更改为
    extendedtemplatedata:(opts,next)->
    以使其异步,并将
    opts.templateData[“getGigsData”]=@getGigsData()
    更改为简单地
    返回@getGigsData(opts,next)

  • 现在我们有了事件和异步调用。我们现在需要让getGigsData的定义支持它。因此,让我们将
    getGigsData:(opts)->
    更改为
    getGigsData:(opts,next)->
    ,以接受我们在步骤3中定义的完成回调(
    next
    )。我们将要做的是,我们将调用next,在那里我们有
    返回gig
    ,所以让我们将
    返回gig
    更改为
    返回next()

  • 现在应该可以了。但是作为一点清理,我们可以通过将
    if err-then console.error“db error”更改为
    return next(err)if err
    来更好地处理错误。您需要修复缩进,因为我们需要删除
    else

  • 考虑到所有这些,再加上一点清洁,您将得到以下结果:

    class mongoPlugin extends BasePlugin
        name: 'mongo'
    
        config:
            hostname: 'mongodb://localhost/test'
    
        # Fetch list of Gigs
        getGigsData: (opts={}, next) ->
            config = @getConfig()
            docpad = @docpad
    
            mongoose.connect(config.hostname)
            db = mongoose.connection
            db.on 'error', (err) ->
                docpad.error(err)  # you may want to change this to `return next(err)`
    
            db.once 'open', -> 
                gigsSchema = mongoose.Schema {
                    date: String,
                    location: String
                }
    
                Gigs = mongoose.model('Gigs', gigsSchema)
    
                Gigs.find {}, (err, gigs) ->
                    mongoose.connection.close()
                    return next(err)  if err
                    return next(null, gigs)
    
            # Chain
            @
    
        extendTemplateData: (opts,next) ->
            @getGigsData null, (err, gigs) ->
                return next(err)  if err
                opts.templateData.gigs = gigs
    
            # Chain
            @
    

    太好了。代码需要最后一个next()才能运行。