简体   繁体   中英

Nested mongoose populate with promises

I am trying to populate my model which looks like:

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

Given an Org, I would like to populate its children, and its childrens children and so on. I can accomplish this for N = 2 levels as such:

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

For hours now I have been trying to accomplish the above using promises, even at N=2. I think that for N = * levels, It would be cleaner to do so with promises which mongoose has a built in implementation of.

        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

I think it should be working as follows:

  1. exec() returns a promise, which I start to handle on the first call to then()
  2. if treeView is false, I return doc, which is seen as a resolution of the original promise and therefore the second then() handler gets called. This does happen.
  3. if treeView is true, the call to Model.populate returns another promise, which will also get handled in the second call to then().

I am getting this Error:

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

I know it gets to the second then()'s error handler, because I have logged out to the console to verify, but I cannot figure out why this is happening. Once I can get this to work, I will try to make it work for N=* levels, which I imagine would involve creating more promises recursively. I have seen many questions here related, but not exactly what I needed.

Any help is greatly appreciated.

I was able to make nested subdocument populate work in MongooseJS v4.1 using the Mongoose promise returned from the mongoose model. No need to use another promise library.

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

Edit consider using .catch() instead of a second function for errors. mpromise now supports .catch() .

Seems like a found a solution for now.

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

What is weird to me is that I need to use mongooses Document.populate and not Model.populate(doc..) which according the the documentation should behave pretty similarly with the exception that one returns a promise. This is one reason I had to use the Q promise api, since Document.populate doesnt return a promise like Model.populate does. I could not get Model.populate to work without a regular node style callback but this solution does what I need. As for N=* levels, I just recursively call Q.ninvoke as many times as I need, extending the path and I can populate as many levels deep as I want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM