mongodbexpress

Optimizing nested collection calls in mongoDb


Im gettin all my registered items and then Im showing a little user rating section under each item listed on the page. Problem is that collection calls are asyn and I cannot send express response when calls are completed. I used quite a bad way to accomplish that by using timeout, so Im looking for better solution suggestions.

router.route('/').get((request, response) => {
      let collection = []
      Item.find({}, function (err, data) {
        if (!err) {
          data.forEach((item) => {
            User.findOne({_id: item.seller}, function (err, res) {
              if (!err) {
                let parse = JSON.parse(JSON.stringify(item))
                let filter
                switch (item.category) {
                  case 'Relics & Antiques':
                    filter = 'antique'
                    break
                  case 'Coin & Currency':
                    filter = 'currency'
                    break
                  case 'Real Estate':
                    filter = 'realestate'
                    break
                  case 'Sports Memorabilia':
                    filter = 'sports'
                    break
                  case 'Fine Art':
                    filter = 'art'
                    break
                  case 'Jewellery':
                    filter = 'jewel'
                    break
                  case 'Automobile':
                    filter = 'auto'
                    break
                }
                parse.rep = res.rep
                parse.sellerName = res.username
                parse.sellerAvatar = res.avatarURI
                parse.filter = filter
                collection.push(parse)
              }
            })
          })
          setTimeout(() => {
            response.render('home/index', {item: collection})
          }, 500)
        }
      })
    })

Solution

  • I've solved the problem thanks to following SO post: how can run mongoose query in forEach loop

    var mongoose = require('mongoose')
    mongoose.Promise = require('bluebird')
    
    router.route('/').get((request, response) => {
      let itemCollection = []
      Item.find({}).then((data) => {
        let userCollection = []
        data.forEach((item) => {
          userCollection.push(User.findOne({_id: item.seller}))
          itemCollection.push(item)
        })
        return Promise.all(userCollection, itemCollection)
      }).then((users) => {
        let results = []
        itemCollection.forEach(function (item, index) {
          let parse = JSON.parse(JSON.stringify(item))
          let filter
          switch (item.category) {
            case 'Relics & Antiques':
              filter = 'antique'
              break
            case 'Coin & Currency':
              filter = 'currency'
              break
            case 'Real Estate':
              filter = 'realestate'
              break
            case 'Sports Memorabilia':
              filter = 'sports'
              break
            case 'Fine Art':
              filter = 'art'
              break
            case 'Jewellery':
              filter = 'jewel'
              break
            case 'Automobile':
              filter = 'auto'
              break
          }
          parse.rep = users[index].rep
          parse.sellerName = users[index].username
          parse.sellerAvatar = users[index].avatarURI
          parse.filter = filter
          results.push(parse)
        })
        response.render('home/index', {item: results})
      })
    })