1

I'm a self taught novice programmer working on a simple web application that uses Angular.js, Node.js, and the graph database neo4j. Right now I'm trying to get a a very basic query to execute and return data to the client. Upon execution I get an error which closes the server.

The following function is executed upon receiving a get request:

exports.test = function (req, res) {
var neo4j = require('neo4j');
var db = new neo4j.GraphDatabase('http://localhost:7474');
var query = [
    'MATCH n',
    'RETURN n.name, n, labels(n)'
];
db.query(query, function (err, results) {
    if (err) {throw err};
    var data = results.map(function(result) {
            return result;
    });
    res.send(data)
}
)};

I get the following error in the console log: java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String

(I can provide the entire log if it would prove useful)

I would be extremely grateful for any insights.

Shrey Gupta
  • 5,509
  • 8
  • 45
  • 71
bornytm
  • 793
  • 1
  • 11
  • 27

2 Answers2

2

The reason for your error is that you're passing an array as a query:

var query = [
    'MATCH n',
    'RETURN n.name, n, labels(n)'
];
db.query(query, function (err, results) { ... }

That should be a string, hence the java.lang.ClassCastException.

So you should either join the query array to make it a string, or don't use an array:

// solution 1
var query = [
    'MATCH n',
    'RETURN n.name, n, labels(n)'
].join(' ');

// solution 2
var query = 'MATCH n RETURN n.name, labels(n)';

Also, this code is a bit superfluous:

var data = results.map(function(result) {
  return result;
});
res.send(data);

Why not use this?

res.send(results);
robertklep
  • 198,204
  • 35
  • 394
  • 381
1

There actually is no issue. It's how Node.js works. Node.js is actually an asynchronous language, meaning that it will execute the next statement WITHOUT waiting for the previous statement to be fully executed. Currently, your code works on the assumption that the variable data will be defined before it is used with res.send(). However, this is NOT the case. What is actually happening is this:

  1. Your code starts mapping the results from the query. The variable data is NOT yet defined.
  2. You perform a method requiring data, which doesn't yet exist.
  3. Your data variable is defined with the callback in your results.map().

This is how the asynchronous behavior of NodeJS works. Basically, callbacks (functions within methods) execute LAST. Thus, you would want to put the res.send() statement in your callback, like so (note that defining the data variable is useless in the first place since it depends on a callback for its value):

results.map(function(result) {
    res.send(result);
});

It is a tough concept to wrap your head around...took me about a week. Let me know if you have any more questions.

Shrey Gupta
  • 5,509
  • 8
  • 45
  • 71
  • @Bagavatu `map()` isn't really appropriate for this, you should use `forEach()` instead. And `res.send()` also isn't appropriate, because that will end the request once it's called (in this case, after the first result). – robertklep Jul 11 '13 at 05:09
  • @robertklep Thanks for the heads up. I simply used whatever functions were being used by the OP. – Shrey Gupta Jul 11 '13 at 05:21
  • @Bagavatu there's nothing wrong with using `res.send()`, but you shouldn't use it in a loop :) – robertklep Jul 11 '13 at 05:28
  • @robertklep haha yeah. I would personally stick all the results in an array and send the array at the last iteration. – Shrey Gupta Jul 11 '13 at 05:30
  • That's completely non-sense! Array.prototype.map isn't asynchronous. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map robertkleps answer is the correct one. – joewhite86 Sep 28 '13 at 21:01
  • Ah, but @joewhite86, map is asynchronously executed in Node.js. I ask that you please do your research and learn about the topic before downvoting answers. – Shrey Gupta Sep 29 '13 at 21:16
  • @Bagavatu That's not true, see here: http://stackoverflow.com/questions/12763613/is-node-js-array-map-asynchronous – joewhite86 Sep 30 '13 at 09:17
  • @Bagavatu And further your answer would send an answer for each element in the array, so it's completely wrong, sorry. – joewhite86 Sep 30 '13 at 09:22
  • In 2017, this is when you would use a Promise chain and/or async/await. Resources to get you started: https://www.promisejs.org/patterns/ and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then – agm1984 Apr 24 '17 at 19:46