Question

I'm having trouble getting mongodb data into nodejs array as follow:

Test db:

{
  "supportTicket" : "viT8B4KsRI7cJF2P2TS7Pd0mfqaI5rtwf",
  "msgId" : 1379304604708.0,
  "username" : "Guest-OSsL2R",
  "message" : "hello",
  "_id" : ObjectId("5236849c3651b78416000001")
}

Nodejs:

function _getMsg(st, callback) {
    db.test.find({ supportTicket: st }).toArray(function (err, docs) {
        callback(docs);
    });
}

var nodeArr = _getMsg('viT8B4KsRI7cJF2P2TS7Pd0mfqaI5rtwf', function (res) {
    console.log(res); // --> res contain data and printed ok
    return res; 
});

console.log('return data: ' + nodeArr )  // --> However, nodeArr  is undefined.

And here is the result:

return data: undefined
return data: undefined
[ { supportTicket: 'viT8B4KsRI7cJF2P2TS7Pd0mfqaI5rtwf',
    msgId: 1379304604708,
    username: 'Guest-OSsL2R',
    message: 'dhfksjdhfkj',
    _id: 5236849c3651b78416000001 } ]
[ { supportTicket: 'viT8B4KsRI7cJF2P2TS7Pd0mfqaI5rtwf',
    msgId: 1379304604708,
    username: 'Guest-OSsL2R',
    message: 'dhfksjdhfkj',
    _id: 5236849c3651b78416000001 } ]

The question is: How can I get data from test db and assign the data to nodeArr?

Was it helpful?

Solution

As you noticed, the console did show the results of the _getMsg call.

_getMsg doesn't return a value, so when you attempt to assign the nodeArr variable to the result, it's getting the value of undefined as there was no return value. Even if you changed it to return a value, at the time of the call to the function the results haven't been returned.

The call to find is asynchronous like much of NodeJs and the MongoDb driver. So, it won't immediately return, and that's why you need the callback to signal when the function has completed. Without that pattern, the function callers will never receive the results.

You've got a return inside of the callback defined: return res. This would return the results back to the function that initiated the call: callback(docs). While there isn't technically any problem with it, there's no reason to do it as the caller already had the results. It's just busy work.

Additionally, I'd be careful about declaring variables in a global scope in NodeJS. With asynchronous behavior (and only one thread doing all the work for all connections), you may find that the value of a global variable is difficult to ascertain at any given moment without inspection.

function _getMsg(st, callback) {
    db.test.find({ supportTicket: st }).toArray(function (err, docs) {
        callback(docs);
    });
}

_getMsg('viT8B4KsRI7cJF2P2TS7Pd0mfqaI5rtwf', function (res) {
    console.log(res); // --> res contain data and printed ok
    var nodeArr = res;  // just moved the nodeArr declaration to function scope
    // *** do next step here, like send results to client
});

If you were sending the results back to the client, inside of the call to _getMsg you might have something like this (assuming that it was in the context of handling an http request) :

response.writeHead(200, { 'Content-Type': 'application/json'});
response.write(JSON.stringify(nodeArr));
response.end();

Which could have been wrapped up in something basic like this:

var http = require('http');
http.createServer(function (req, response) {
    // all requests return the results of calling _getMsg
    // this function won't return until the callback completes
    _getMsg('viT8B4KsRI7cJF2P2TS7Pd0mfqaI5rtwf', function (nodeArr) {        
        response.write(JSON.stringify(nodeArr));
        response.end();
    });
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

OTHER TIPS

You can do this:

var nodeArr;
function _getMsg(st, callback) {
    db.test.find({ supportTicket: st }).toArray(function (err, docs) {
        callback(docs);
    });
}

_getMsg('viT8B4KsRI7cJF2P2TS7Pd0mfqaI5rtwf', function (res) {
    console.log(res); 
    nodeArr = res; 
});

console.log('return data: ' + nodeArr ) 

But normally is a terrible idea and in your case the console.log will still show it like undefined. This is because the asignation will be done when the query finish but node will be still executing code until that happens.

Normally you should cosume the data and do whatever you want to do in the callback of _getMsg. It's the safe way to work in most cases.

You need to understand concepts between async and sync flow.

db.test.find({ supportTicket: st }).toArray(function (err, docs) {
  if (err) throw err;
  nodeArr = docs;
});

logindata.find({ Name: req.body.username }).select().exec(function (err, data) { })

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top