2

I'm having a lot of trouble getting the chained mongoose commands run in sequential order when using async/await. A simple await Model.find({}) command works as one might expect in an asynchronous function, but when I chain find commands with lean, populate, and exec for the purposes of deep population (http://mongoosejs.com/docs/populate.html#deep-populate) I am not able to run them in order as I'd like.

const messageSchema = new Schema({
  ...
})
const Message = mongoose.model("message", messageSchema)

const chatSchema = new Schema({
  conversations: [{
      messages: [{ type: Schema.Types.ObjectId, ref: "message" }]
  }]
})
const Chat = mongoose.model("chat", phoneSchema)

console.log("11111111111")

const chat = await Chat.findOne({ ... })
  .lean()
  .populate({ path: "conversations" })
  .exec(async (err, docs) => {
    const options = {
      path: "conversations.messages",
      model: "message",
    }

    const result = await Chat.populate(docs, options,
      (e, foundChat) => foundChat)

    console.log("22222222222")

    return result
  })

console.log("333333333333")

Result:

11111111
33333333
22222222

Desired Result:

111111111
222222222
333333333
Trevor
  • 1,284
  • 3
  • 15
  • 33

2 Answers2

3

Not sure why, tried a lot of different things, but this works.

const chat = await Chat.findOne({ ... })
  .populate({
    path: "conversations.messages",
    model: "message",
  })
  .exec((error, foundChat) => foundChat)
Trevor
  • 1,284
  • 3
  • 15
  • 33
2

I feel like your code has 2 issues:

  1. You cannot call populate() after you used the lean() option. Lean() turns the returned objects into regular javascript objects and not mongoose documents. Populate is a built-in method in mongoose, so you can only use it in mongoose documents. This has nothing to do with your question but it's important to know.

  2. When you call exec() on a query and pass a callback as parameter, it does not return a promise and therefore the 'await' clause has no effect over it. That's why your function is not waiting for Chat.findOne() to resolve and goes straight to the last console.log. The following would probably work:

    const chat = await Chat.findOne({ ... })
     .populate({ path: "conversations" })
     .exec().then(async (docs) => {
       const options = {
         path: "conversations.messages",
         model: "message",
       }
    
       const result = await Chat.populate(docs, options)
    
       console.log("22222222222")
    
       return result
    })
    
Felipe Vignon
  • 451
  • 3
  • 9