嵌套的猫鼬填充了承诺

Posted

技术标签:

【中文标题】嵌套的猫鼬填充了承诺【英文标题】:Nested mongoose populate with promises 【发布时间】:2014-09-16 12:48:34 【问题描述】:

我正在尝试填充我的模型,如下所示:

var Org = new mongoose.Schema(
        _id: type: String, unique:true, //this will be the org code
        name: String,
        level: String,
        children: [type: String, ref: 'Org']
    );

//Orgs have children orgs, which themselves can have children orgs at N levels

给定一个组织,我想填充它的孩子,以及它的孩子的孩子等等。我可以为 N = 2 个级别完成此操作:

     req.Model.findOne(_id: id).populate('children').exec(function(err, doc)
        if (err)
            return next(err);
        
        req.Model.populate(doc, path: 'children.children', function(err, doc)
            if(err)
                return next(err);
            
            return res.json(doc);
        );
    );

几个小时以来,我一直在尝试使用 Promise 完成上述任务,即使在 N=2 时也是如此。我认为对于 N = * 级别,使用 mongoose 内置实现的 Promise 这样做会更干净。

        req.Model.findOne(_id: id).populate('children').exec()
        .then(function (doc)
            if(!treeView) 
                return doc;
            
            return req.Model.populate(doc, path: 'children.children');
        )
        .then(function (doc)
            return res.json(doc);
        ,function(err)
            return next(err);
        );

// treeView is a query string that lets me know that I need to populate the refs

我认为它应该如下工作:

    exec() 返回一个 promise,我在第一次调用 then() 时开始处理它 如果 treeView 为假,我返回 doc,这被视为原始承诺的解决方案,因此第二个 then() 处理程序被调用。这确实发生了。 如果 treeView 为真,对 Model.populate 的调用将返回另一个承诺,该承诺也将在第二次调用 then() 时得到处理。

我收到此错误:


   "status": "error",
   "serverTimestamp": "2014-07-24T18:23:02.974Z",
   "message": "\"function\" == \"undefined\""

我知道它会到达第二个 then() 的错误处理程序,因为我已经注销到控制台进行验证,但我无法弄清楚为什么会发生这种情况。一旦我可以让它工作,我将尝试让它在 N=* 级别上工作,我想这将涉及递归地创建更多的 Promise。我在这里看到了很多相关的问题,但不完全是我需要的。

非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

我能够使用从 mongoose 模型返回的 Mongoose 承诺在 MongooseJS v4.1 中使嵌套子文档填充工作。无需使用其他 Promise 库。

var fuelOrderId = req.params.fuelOrderId;
fuelOrderModel.findById(fuelOrderId).populate('aircraftId')
.then(function(order)
    return fuelOrderModel.populate(order,
         path: 'aircraftId.aircraftContacts', 
          model: 'aircraftContactModel');
)
.then(function(result)
    res.json(
        fuelOrder: result,
        status: 1
    );
,function(err)
    console.error(err);
    res.json(err: err, status: 0);
)

编辑考虑使用.catch() 而不是第二个函数来解决错误。 mpromise 现在支持.catch()

【讨论】:

【参考方案2】:

现在似乎找到了解决方案。

Q.ninvoke(doc, 'populate',path: children.children)
.then(function(doc)
    return res.json(doc);
,function(err) 
    return next(err);
);

对我来说奇怪的是我需要使用猫鼬 Document.populate 而不是 Model.populate(doc..) 根据文档应该表现得非常相似,除了一个返回一个承诺。这是我不得不使用 Q Promise api 的原因之一,因为 Document.populate 不会像 Model.populate 那样返回 Promise。如果没有常规的节点样式回调,我无法让 Model.populate 工作,但这个解决方案可以满足我的需要。至于 N=* 级别,我只是根据需要递归调用 Q.ninvoke 多次,扩展路径,我可以根据需要填充任意深度的级别。

【讨论】:

似乎这是使 document#populate 适合承诺链的唯一方法。谢谢。

以上是关于嵌套的猫鼬填充了承诺的主要内容,如果未能解决你的问题,请参考以下文章

更新混合类型的猫鼬嵌套数组

如何填充新创建的猫鼬文档?

具有多个子路径的猫鼬填充路径

如何使用外键数组在没有 _id 的猫鼬中填充?

构建我的猫鼬模式的最佳方式:嵌入式数组、填充、子文档?

如何使用 mongoose 填充具有无限嵌套级别的文档