2

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}`));
2
  • Does this answer your question? How do I return the response from an asynchronous call? Commented Aug 11, 2022 at 22:21
  • I went through a few changes based on some of the suggestionsin it, but I could not make any of them work any better. I think it comes from a shallow understanding of what JavaScript does :( Commented Aug 12, 2022 at 2:17

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

10 Comments

now the full code is there is the solution any different ? I tried what you said, but in the return at the bottom, it returns nothing.
Can't believe I am struggling so hard with this, have watched videos on promises and callbacks, and kind of get the gist of it. but I can't implement it in this file, so I must have something else out-of-whack...
anyone else care to have a crack at this ... I am stumped, every tutorial I read, or video, they are just not quite the same as my case ... but a more skilled operator might see it straight away ?
I've used the little detailed code you've supplied to show you how to do it, for the return you can simply just return res.json(answers). I'll modify the code, my suggested solution is shorter and uses ES6 new async/await
Code updated supposing that this piece of code would be executed inside a middleware and would return the answers as JSON. Could you at least try it and let me know? It's shorter, more modern solution and it was first
|
1

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);
          })

    }
      
    }
  })

7 Comments

very close, in the logging I am getting a couple of <1 empty item> in the console.log("ANSWERS", answers), then when that is finished printing to console, I get a belated `NAME >>>>> etc" with the "empty" ones ?? I will investigate further
@Brett did you replace the for loop? try the new code
yes, I replaced it with yours,
@Brett did it work now? I also added .push to the answers, that's probably what's causing empty elements..
Boom, that did it, thank you SO much ... I have spent to long trying to solve this
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.