javascript - How to add each result of the last loop within two nested searches in an array to show the full result in NodeJS and Mongoose? -


i'm beginner in both stackoverflow , nodejs/mongoose, i'm sorry if have error or break rule. thank in advance.

i need function return nearby products there in location, given through user wich "id" request called "user".

i try making function, finalproducts return products exit @ search, when try add component of result body finalproducts return data empty. error following:

  throw er; // unhandled 'error' event   ^ 

error: can't set headers after sent. @ serverresponse.setheader (_http_outgoing.js:371:11) @ serverresponse.header (/home/frangaliana/escritorio/client-thingy/node_modules/express/lib/response.js:730:10) @ serverresponse.send (/home/frangaliana/escritorio/client-thingy/node_modules/express/lib/response.js:170:12) @ serverresponse.json (/home/frangaliana/escritorio/client-thingy/node_modules/express/lib/response.js:256:15) @ serverresponse.send (/home/frangaliana/escritorio/client-thingy/node_modules/express/lib/response.js:158:21) @ /home/frangaliana/escritorio/client-thingy/controllers/product.js:200:41 @ /home/frangaliana/escritorio/client-thingy/node_modules/mongoose/lib/query.js:2916:18 @ newtickhandler (/home/frangaliana/escritorio/client-thingy/node_modules/mpromise/lib/promise.js:234:18) @ _combinedtickcallback (internal/process/next_tick.js:73:7) @ process._tickcallback (internal/process/next_tick.js:104:9)

i show code , models understand trouble:

function search nearby products in controller product.js:

function getnearbyproducts(req, res) {   let userid = req.user;   let point;    var geooptions = {     spherical: true,     maxdistance: 500   }    user.findbyid(userid, {password:0})     .populate('location','coordinates')     .exec(function (err, result) {         if (err) console.log('no se ha podido encontrar la localización')          point = {           type: "point",           coordinates: [parsefloat(result.location.coordinates[0]),parsefloat(result.location.coordinates[1])]         }          location.geonear(point,geooptions, function(err, resultlocations) {           for(var = resultlocations.length - 1 ; >= 0 ; i--){             var nearlocation = resultlocations[i].obj.id             var queryuser = {"location": nearlocation}              user.find(queryuser)               .exec(function (err, resultusers) {                 for(var j = resultusers.length - 1 ; j >= 0; j--) {                   if(resultusers[j] !== undefined){                     var exactuser = resultusers[j].id                      var limit;                      if(req.query.limit) {                       limit = parseint(req.query.limit)                       if(isnan(limit)){                         return next(new error())                       }                     } else {                       limit = 10;                     }                      var queryproduct = {"user": exactuser}                      if(req.query.before) {                       queryproduct = {"user": exactuser, "_id" : {$lt: req.query.before}};                     }else if (req.query.after) {                       queryproduct = {"user": exactuser, "_id" : {$gt: req.query.after}};                     }                      product.find(queryproduct)                       .limit(limit)                       .populate('user')                       .exec(function (err, resultproducts) {                          var finalproducts = [];                         for(var k = resultproducts.length - 1 ; k >= 0; k--){                             if(resultproducts[k] !== undefined){                               finalproducts.push(resultproducts[k])                             }                         }                          if(finalproducts.length > 0){                           if(req.query.before){                             products.reverse();                           }                           var finalresult = {                                 data: finalproducts,                                 paging: {                                   cursors: {                                     before: finalproducts[0].id,                                     after: finalproducts[finalproducts.length-1].id                                   },                                   previous: 'localhost:3000/api/products?before='+finalproducts[0].id,                                   next: 'localhost:3000/api/products?after='+finalproducts[finalproducts.length-1].id,                                 },                                 links: {                                   self: 'localhost:3000/api/products',                                   users: 'localhost:3000/api/users'                                 }                               }                           } else {                               var finalresult = {                                     data: finalproducts,                                     paging: {                                     cursors: {                                       before:undefined,                                       after:undefined                                       },                                       previous: undefined,                                       next: undefined                                     },                                     links: {                                       self: 'localhost:3000/api/products',                                       users: 'localhost:3000/api/users'                                     }                                   }                           }                          res.status(200).send(finalresult);                       })                   }                 }               })           }         })    }) }) 

models:

user.js

'use strict';  const mongoose = require('mongoose'); const schema = mongoose.schema; const bcrypt = require('bcrypt-nodejs'); const location = require('../models/location'); const crypto = require('crypto');  const userschema = new schema({   email: {     type: string,     lowercase: true,     //añadir campo unique: true para que sólo se pueda registrar un email   },   name: string,   password: string,   userimg: string,   gender: boolean,   birthdate: date,   signupdate: {     type: date,     default: date.now(),   },   location:{     type: schema.objectid,     ref: 'location'   } });  userschema.pre('save', function(next) {   let user = this;   if (!user.ismodified('password')) return next();    bcrypt.gensalt(10, (err, salt) => {     if (err) return next(err);      bcrypt.hash(user.password, salt, null, (err, hash) => {       if (err) return next(err);        user.password = hash;       next();     });   }); });  userschema.methods.gravatar = function() {   if(!this.email) return `https://gravatar.com/avatar/?s=200&d=retro`    const md5 = crypto.createhash('md5').update(this.email).digest('hex')   return `https://gravatar.com/avatar/${md5}?s=200&d=retro` }  module.exports = mongoose.model('user', userschema); 

product.js

'use strict'  const mongoose = require('mongoose'); const schema = mongoose.schema; const user = require('../models/user');  var max = [5 , 'the value of ({value}) exceeds limit ({max}). '] var min = [1 , 'the value of ({value}) beneath limit ({min}). ']  const productschema = schema({   title: string,   price: {     type: number,     default: 0   },   user: {     type: schema.objectid,     ref: 'user'   },   categoryproduct: {     type: string,     enum:['moda y accesorios', 'motor', 'electrónica', 'deporte', 'libros, música y películas', 'electrodomésticos', 'servicios', 'muebles y decoración', 'otros'],     default: 'electrónica'   },   description: {     type: string,     default: 'objeto para vender'   },   visits: {     type: number,     default: 0   },   status: {     type: boolean,     default: false   },   publicationdate: {     type: date,     default: date.now()   },   salesrating: {     type: number,     max: max,     min: min,     default: 1   },   salescomment: {     type: string,     default: 'perfecto'   } })  module.exports = mongoose.model('product', productschema); 

location.js

'use strict';  const mongoose = require('mongoose'); const schema = mongoose.schema;  const locationschema = new schema({   type: {     type: string,     default: "point"   },   coordinates: {     type: [number],     index: "2dsphere",     default: [38.280153, -0.712901]   } })  module.exports = mongoose.model('location', locationschema); 

i hope question can resolved or @ least explain me because doesn't work well. lot of again!

edit: (because have fix problem)

thanks skirtle gave me idea solve this.

i didn't control asynchronous calls threw searches mongoose , generated multiple responses, told me started using promises keep track of them when result throwing me array of id's whether user, location or product treated them 1 one.

i recalled mongoose query accompanied filter {$in:[array]} returned results containing of these id's (in case) had array looking this:

function getnearbyproducts(req, res) {   var userid = req.user;    var promiseuser = user.findbyid(userid, {password: 0})     .populate('location')     .exec()    promiseuser     .then(function(result){       return result.location;     })     .then( function(resultuser){         return location.geonear(                 {type:'point', coordinates: [parsefloat(resultuser.coordinates[0]),parsefloat(resultuser.coordinates[1])]},                 {maxdistance:100000, spherical: true}               ).then(function(locsgeonear){                 var resultgeonear = []                 for(var = locsgeonear.length - 1; >= 0; i--){                   if(resultuser.id != locsgeonear[i].obj.id){                     resultgeonear.push(locsgeonear[i].obj.id)                   }                 }                 return resultgeonear               })     })     .then(function(resultsearchlocs){       var queryusersbylocation = {'location': {$in: resultsearchlocs}}        return user.find(queryusersbylocation, {password: 0})               .exec()              .then(function(userssearchs){                var resultusers = []                for(var = userssearchs.length - 1; >= 0; i--){                  if(userid != userssearchs[i].id){                    resultusers.push(userssearchs[i].id)                  }                }                return resultusers              })     })     .then(function(resultsearchusers){       var limit;        if(req.query.limit) {         limit = parseint(req.query.limit)         if(isnan(limit)){           return next(new error())         }       } else {         limit = 10;       }        var queryproductsbyusers = {'user': {$in: resultsearchusers}}       //para obtener la página anterior un id       if (req.query.before) {         queryproductsbyusers = {'user': {$in: resultsearchusers}, "_id" : {$lt: req.query.before}};       //para obtener la página posterior un id       } else if (req.query.after) {         queryproductsbyusers = {'user': {$in: resultsearchusers}, "_id": {$gt: req.query.after}};       }        return product.find(queryproductsbyusers)               .limit(limit)               .exec()     })     .then(function(resultsearchproducts){       if(resultsearchproducts.length > 0){         if(req.query.before){           resultsearchproducts.reverse();         }          var resultfinal = {               data: resultsearchproducts,               paging: {                 cursors: {                   before: resultsearchproducts[0].id,                   after: resultsearchproducts[resultsearchproducts.length-1].id                 },                 previous: 'localhost:3000/api/products?before='+resultsearchproducts[0].id,                 next: 'localhost:3000/api/products?after='+resultsearchproducts[resultsearchproducts.length-1].id,               },               links: {                 self: 'localhost:3000/api/products',                 users: 'localhost:3000/api/users'               }             }      } else {        var resultfinal = {              data: resultsearchproducts,              paging: {              cursors: {                before:undefined,                after:undefined                },                previous: undefined,                next: undefined              },              links: {                self: 'localhost:3000/api/products',                users: 'localhost:3000/api/users'              }            }      }       res.setheader('content-type', 'application/json');      res.status(200).send(resultfinal);     })     .catch(function(err){       console.log(`${err}`)     }) } 

many community above skirtle gave me keys reach solution.

greetings!

if add following logging before call send:

console.log('sending response'); res.status(200).send(finalresult); 

i believe you'll find you're calling send multiple times on same request, isn't allowed. when call send first time request/response on , attempt send more data result in error.

i'm struggling follow code believe cause looping you're doing. need wait until db queries done , you've gathered final data before call send.

you may find promises useful way reduce complexity in products.js if don't fancy using them highly recommend bit of refactoring make file intelligible. general rule pyramid of doom sign you've got problems https://en.wikipedia.org/wiki/pyramid_of_doom_(programming)


Comments

Popular posts from this blog

ZeroMQ on Windows, with Qt Creator -

unity3d - Unity SceneManager.LoadScene quits application -

python - Error while using APScheduler: 'NoneType' object has no attribute 'now' -