get mongodb data to nodejs array?

Đức Nguyễn picture Đức Nguyễn · Sep 16, 2013 · Viewed 16.1k times · Source

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?

Answer

WiredPrairie picture WiredPrairie · Sep 16, 2013

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/');