0

I am new to async and await. Every thing works fine but in final output last value in result, mcount is not returning. Means aggregation output is returning slowly.

Profile and Userinfo are two separate schemas.

flist (req, res){
    Profile.findById(req.user)
    .select('list.users -_id')
    .exec(function (err, result){
      if(err){
        res.status(400).send("Invalid request")
      }
      if(result.list.users.length >= 1){
          uinfo(result.list.users, req.user)
          .then(value =>{           
            console.log(value)
              res.status(200).send({
                friends : value
              })
          })
          .catch(err => {
              res.status(400).send("Invalid request")
            })          
      }else{
        res.status(200).send("No result")
      }
    })
  }

list.users is nested object with id fields. Below one is uinfo function

async function uinfo(data, user){
    const arr = []
    for(let i of data){
      await Userinfo.findById(i.id, 'name', function(err, success){
        if(err){
          res.status(400).send("Invalid request")
        }
        const obj = success.toObject()
        Profile.aggregate([{"$match": {"_id": {"$in": [user, i.id]}}}, {"$unwind": "$list.users"}, {"$group": {_id: "$list.users.id", count: {$sum: 1}}}, {$match: {count: 2}}, {$project: {_id: 1}}], function(err, result){
          if(err){
            res.status(400).send("Invalid request")
          }
          if(result.length >= 1){
            obj.mcount = result.length
          }
          else{
            obj.mcount = 0
          }
        })
      arr.push(obj)

      })
    }
    return arr
}

Below one is the output where in last one it is missing mcount.

   [   { _id: 5aba75ef60b6c909a859a312,
    name: 'user1',
    mcount: 0 },
  { _id: 5abbc6fcafafad143a4d4f85,
    name: 'user2',
    mcount: 1 },
  { _id: 5aba761160b6c909a859a318, name: 'user3' } ]
code.mevn
  • 155
  • 1
  • 2
  • 10

2 Answers2

0

Using await in a for loop like this can really slow you down sometimes, see In JavaScript, does using `await` inside a loop block the loop?. What you might do instead is something like this:

const arr = await Promise.all(data.map(i => {
   // whatever stuff you want to do with the data
}))
return arr

I don't know if this will solve the problem with the last one, but it will speed up what you're trying to do.

JSilv
  • 1,035
  • 12
  • 26
0

You are mixing syntaxes with await-async, callback, and Promise. Don't do that.

This is the best I could do. I would seriously consider a rewrite and only use async-await. The code below is untested.

Error handling is omitted.

const flist = async (req, res) => {
    const users = await Profile.findById(req.user)
        .select('list.users -_id')
        .exec()

    if (result.list.users.length >= 1) {
        const friends = await uinfo(result.list.users, req.user)
        res.status(200).json({
            friends
        })
    } else {
        res.status(400).json()
    }
}

async function uinfo(data, user) {
    const arr = []
    const promises = []

    // You can not mix synchronous with asynchronous operations
    for (const i of data) {
        promises.push(Userinfo.findById(i.id, 'name').exec())
    }

    // Wait for all Promises to complete.
    // Returns an array of values from the iteration above
    const success = await Promise.all(promises)

    // 0 is "falsey"
    if (!success.length) {
        // error
    }

    // Since you're only looking for one user, if the above check is fine then pull it from the array
    const obj = success[0].toObject()

    const result = await Profile
        .aggregate([{"$match": {"_id": {"$in": [user, obj.id]}}}, {"$unwind": "$list.users"}, {"$group": {_id: "$list.users.id", count: {$sum: 1}}}, {$match: {count: 2}}, {$project: {_id: 1}}])
        .exec()

    if (result.length >= 1) {
        obj.mcount = result.length
    } else {
        obj.mcount = 0
    }

    arr.push(obj)

    return arr
}
Cisco
  • 20,972
  • 5
  • 38
  • 60