1

I am creating and Node project using with MongoDB. I have two files such as change_language.js and admin_event.js. I have created a function in change_language.js file and I called that function from other file (admin_event.js).

change_language.js

const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
var assert = require('assert');
const request = require("request");
const Entity_option = require("../models/entity_option");
var ObjectId = require('mongodb').ObjectID;
require("../routes/admin_event");

function change_language(language_id)
{
      let myRes=[];
      Entity_option.aggregate([
        {$match:{"language_id":ObjectId(language_id)}}

        ], function (err, result)
        {
            if (err)
            {
                myRes=err;
            }
            else
            {   
                myRes= result;  
            }
            console.log(myRes); // Print 1
        })
    return myRes;
}

module.exports.change_language = change_language;

admin_event.js

const express = require("express");
const router = express.Router();
const Event = require("../models/event");
const myLan=require("../setting/change_language").change_language;
var ObjectId = require('mongodb').ObjectID;

    let language_id="5b9f5b324ae85e12a869187c";

    let x = myLan(language_id);
    console.log(x); // Print 2

module.exports = router;

The function works as expected. console.log(myRes) (Print 1 line) shows the output in command prompt. But when I call that function from another file (console.log(x)) shows undefined. Why?

  • 2
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – ponury-kostek Sep 18 '18 at 08:11
  • @ponury-kostek, No this is from Node.JS –  Sep 18 '18 at 08:13

1 Answers1

1

As @ponury-kostek said, this is actually a duplicate of a common problem with people who are new to Node.js.

The function change_language is an async function, but you're returning a value before that async task has had a chance to complete.

What is an async function? Nodejs traditionally uses callbacks which you've already explored here, just with a slight misunderstanding.

Entity_option.aggregate([{
  $match:{"language_id":ObjectId(language_id)}
}], function (err, result) {
  if (err) {
    myRes=err;
  }
  else {
    myRes= result;  
  }

  console.log(myRes); // => 1
})

Here we are making a function call which returns a callback. This callback function (the function that takes an error and result) is not called until the main function (Entity_option.aggregate) finishes. This could be at any time and so you cannot rely on immediately returning any values from the wrapper function. As a result we need to use some nested callbacks to make all of your code async.

In your existing code, you're trying to assign myRes to result, but the return call was outside this callback and so has been called way before this callback has triggered. Which is why you're getting undefined. Basically, you're not waiting for the async task to complete. It's like putting bread into the toaster, pushing it down but immediately trying to return the toast. It of course isn't ready yet!

Here's a sample of how your code should look.

change_language.js

// All your various requires etc...
function change_language(language_id, callback) {
  let myRes=[];
  Entity_option.aggregate([{
      $match:{"language_id":ObjectId(language_id)}
    }], function (err, result) {
        if (err) {
            myRes=err;
        } else {   
            myRes= result;  
        }

        callback(err, result);
    });
}

module.exports.change_language = change_language;

admin_event.js

const express = require("express");
const router = express.Router();
const Event = require("../models/event");
const myLan=require("../setting/change_language").change_language;
var ObjectId = require('mongodb').ObjectID;

let language_id="5b9f5b324ae85e12a869187c";

// Supply a callback as this is an async call
// the callback will be triggered once the async
// process (such as talking to a database) has finished
// or errored.
myLang(language_id, function(err, result) {
  let x = result;

  console.log(result);
});

module.exports = router;

If we do this, you'll quickly see some issues with callback style code. So I'd point you towards looking at JavaScript "Promises" and async/await, but those are outside the scope of this question.

Elliot Blackburn
  • 3,759
  • 1
  • 23
  • 42
  • Thank you so much. As you told I am new to Node.Js. And Thanks for your efforts. Could you please tell me the differs of Async and Callback? –  Sep 18 '18 at 10:04
  • Async just means asynchronous, this is a term which means something happens on it's own, separately, and most importantly the system does not wait for that thing to run before continuing on with the next line of code. A callback is simply a function which is traditionally called once something has completed. Callbacks and the "Event loop" (google this) are how Nodejs traditionally operate asynchronously. Async programming, callbacks, js promises, and js async/await are all topics you should spend some time researching. – Elliot Blackburn Sep 18 '18 at 14:29
  • @SAKTHY, feel free to learn async programming with callbacks before continuing onto anything else. – Elliot Blackburn Sep 18 '18 at 14:29
  • @SAKTHY if this answer was correct, could you give it a Tick (mark it as correct)? – Elliot Blackburn Sep 18 '18 at 14:29
  • 1
    Sure, Thank you Elliot Blackbum –  Sep 18 '18 at 17:49