Home > Enterprise >  node.js trying to pass variables around like I would in python
node.js trying to pass variables around like I would in python

Time:08-12

I am new to javascript, I am trying to pass the result of a nested function, down to the rest of the parent function ? maybe?

I have documents in one mongodb collection, and company info in another. So I am trying to pair them up like this part of the code, but it is not doing what I am trying to get done. I think I am clearly missing something about javascript and the way it functions.

I am able to get the list of companies, and log to the console, but I can't do what I am doing at this line

'name': companies[0]['name'],

const mongoose = require('mongoose');
const express = require('express');
var cors = require('cors');
const bodyParser = require('body-parser');
const logger = require('morgan');
const {Data, Companies} = require('./data.js');


const API_PORT = 3001;
const app = express();
app.use(cors());
const router = express.Router();



const dbRoute = 'mongodb://192.168.200.20/matrix';

mongoose.connect(dbRoute, { useNewUrlParser: true, useUnifiedTopology: true});

let db = mongoose.connection;

db.once('open', () => console.log('connected to the database'));

db.on('error', console.error.bind(console, 'MongoDB connection error:'));

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(logger('dev'));


router.post("/searchData", (req, res, next) => {
  console.log("REQ---", req.body.search_obj)
  let answers = []
  let search_query = req.body.search_obj
  let arg_group = [];
  let arg_template = [];
  let arg_object = {}
  for (i in search_query){
    arg_query = {search_text: { $regex: new RegExp(search_query[i]), $options: 'i' }}
    arg_group = arg_group.concat(arg_query)
  }
  arg_template = arg_template.concat(arg_group)
  arg_list = "\"{$and: ["   arg_group   "]}\""
  arg_object['$and'] = arg_template

  Data.find(arg_object, function (err, data){
    if (err){
      console.log(err);
    }
    else {
      console.log("LENGTH", data.length)
      for (i in data) {
        console.log("Resolved to ... : ", data[i]['_id'], data[i]['title']);
        Companies.find({_id: data[i]['_id']})
          .then(companies => {
            console.log("Company Name:")
            console.log("NAME >>>> >>>> ", companies[0]['name']);

          })
          .catch(err => {
            console.log(err);
          })

        search_reply = {
          '_id': data[i]['_id'],
          'title': data[i]['title'],
          'url': data[i]['url'],
          'release_date': data[i]['release_date'],
          'document_date': data[i]['document_date'],
          'name': companies[0]['name'],
        }
        answers[i] = search_reply

    }

      console.log("LENGTH", data.length)
      console.log("ANSWERS", answers)
      console.log("LENGTH", data.length)
      return res.json(answers);
    }
  })

});



router.post('/updateData', (req, res) => {
  const { id, update } = req.body;
  Data.findByIdAndUpdate(id, update, (err) => {
    if (err) return res.json({ success: false, error: err });
    return res.json({ success: true });
  });
});


router.delete('/deleteData', (req, res) => {
  const { id } = req.body;
  Data.findByIdAndRemove(id, (err) => {
    if (err) return res.send(err);
    return res.json({ success: true });
  });
});

router.post('/putData', (req, res) => {
  let data = new Data();

  const { id, message } = req.body;

  if ((!id && id !== 0) || !message) {
    return res.json({
      success: false,
      error: 'INVALID INPUTS',
    });
  }
  data.message = message;
  data.id = id;
  data.save((err) => {
    if (err) return res.json({ success: false, error: err });
    return res.json({ success: true });
  });
});

app.use('/api', router);

app.listen(API_PORT, () => console.log(`LISTENING ON PORT ${API_PORT}`));

CodePudding user response:

the problem is that node.js runs asynchronously, so you return results before Companies.find is done. so you should return results only when everything is finished, which means you need to send results from Companies.find.

since you're iterating over many results, a quick and dirty way (the whole code should be rewritten otherwise) to know when everything is done is to add a counter and then return when the last loop is done (replace for..in loop with for loop to get a numeric index)

try this:

  Data.find(arg_object, function (err, data){
    if (err){
      console.log(err);
    }
    else {
      console.log("LENGTH", data.length)
      for (let i = 0; i < data.length; i  ) {
        console.log("Resolved to ... : ", data[i]['_id'], data[i]['title']);
        Companies.find({_id: data[i]['_id']})
          .then(companies => {
            console.log("Company Name:")
            console.log("NAME >>>> >>>> ", companies[0]['name']);


           let search_reply = {
              '_id': data[i]['_id'],
              'title': data[i]['title'],
              'url': data[i]['url'],
              'release_date': data[i]['release_date'],
              'document_date': data[i]['document_date'],
              'name': companies[0]['name'],
            }
            answers.push(search_reply)

            if(i 1==data.length) {
                  console.log("LENGTH", data.length)
                  console.log("ANSWERS", answers)
                  console.log("LENGTH", data.length)
                  return res.json(answers);
            }

          })
          .catch(err => {
            console.log(err);
          })

    }
      
    }
  })

CodePudding user response:

You can either move all of your search_reply logic inside promise then callback. The other solution which could be easier is to use async/await for handling Promises. Let's first assume that your parent function is called getSearchResults, so based on that your code would look like:

try {
    const data = await Data.find(arg_object);
    console.log("LENGTH", data.length)
    for (const answer in data) {
        console.log("Resolved to ... : ", answer['_id'], answer['title']);
        const companies = await Companies.find({ _id: answer['_id'] });

        search_reply = {
            '_id': answer['_id'],
            'title': answer['title'],
            'url': answer['url'],
            'release_date': answer['release_date'],
            'document_date': answer['document_date'],
            'name': companies[0]['name'],
        }
        answers.push(search_reply);
    }

    console.log("LENGTH", data.length)
    console.log("ANSWERS", answers)
    console.log("LENGTH", data.length)
} catch (err) {
    console.log(err);
}

Updates: This updated piece of code should replace DB access code inside router.post("/searchData", (req, res, next) => {...} endpoint. Starting from Data.find(arg_object, function(err, data) {...}

Fixed answers to match the for .. in loop, instead of using index.

It's using async/await for handling promises and try/catch for handling errors

  • Related