1

I want to populate a non-id field with mongoose, and already found these questions here:

link1

link2

It turns out that mongoose didn't support this functionality now. The open issue here:https://github.com/Automattic/mongoose/issues/2562

So now, I want to populate manually with extra queries. But I have some problems in doing it

I have two schema (replies, users):

Here is the replies schema, which the author_id referencing to the user's collection's username field not _id;

var ReplySchema = new Schema({
  'content' : {
    type: String,
    required: true

  },
  'author_id' : {
    type:  String,
    ref: 'users'
  },
});

When I got the entire replies. like:

replies [ {
    content: 'comments one',
    author_id: 'raynlon',
    },
  { 
    content: 'comments two',
    author_id: 'raynlon',
  } ]

FROM here, i'm doing a further step to query the author from User table, what I did is:

 var replies = yield query.exec(); // which already got all the replies  
    var final = [];  

   for (var i = 0; i < replies.length; i++) {
    co(function*(){
      var data = yield User.Model.findOne({username: replies[i].author_id}).select('username email avatar gravatar_id name').exec();
      return data;
    }).then(function(value) {
      final.push(value);
    });
  }

    return final // I need to return the modified data back to the client

I always got empty [];

this is due to the async code inside for loop?

I also found some solutions, like: Promise.all(), q.all() these kinda parallel promise stuff....

but I don't know how to do..

the co library I used said the co() should returned as a promise, theoretically, we could then inject into Promise.all([]), but it doesn't work...so could anyone help me about this?

Community
  • 1
  • 1
L.G
  • 165
  • 2
  • 9

1 Answers1

0

Ok, the problem: you created the variable final and returns it afterwars, this happens just before the Mongo-Query has executed.

Solution: You should push the Promises to final, and then resolve it all together when you reply to the client.

function queryAsync() {
  var replies = yield query.exec(); // which already got all the replies  
  var final = [];

  for (var i = 0; i < replies.length; i++) {
    final.push(
      User.Model.findOne({
        username: replies[i].author_id
      }).select('username email avatar gravatar_id name').exec()
    )
  }

  return final; // and array with promises is returned
}

// later in your handler ..
function handler(request, response) {
  // ..

  // query here, and resolve promises in final here
  bluebird.all(queryAsync()).then(function(final) {
    // all promises resolved
    response.send(final);
  })

  // ..
}
alwe
  • 1,485
  • 17
  • 22