Bruce MacDonald
Bruce MacDonald

Reputation: 288

Parsing complex JSON results from Neo4j

First, Thanks in advance for reading this. Second, Sorry in advance for the long post - but I hope like a well-written function, the good stuff is at the top - although please take the time to read it all. Third, I've lost track of how many stack questions I've looked through - if this is still a noob question I apologize.

I'm using Node.js to provide api's for my AngularJS client. All my data aggregation and transformation will be done in Node and present a flat JSON data structure to the client.

I have a Neo4j model that relates me to the applications I'm responsible for and relates technical risks to all applications. I have a nice Cypher query that shows me the tech risks for only the applications that I'm responsible for and excludes all my other apps that have no risk. Here's a pic of my query results: Neo4j Graph result.

Here's my node.js code (file routes.js called by the main api.js file):

var router = require('express').Router();
var neo4j = require('neo4j');
var db = new neo4j.GraphDatabase('http://user:password@localhost:7474');

router.get('/techrisks', getTechRisks);

module.exports = router;

function getTechRisks(req, res) {

    db.cypher({
        query: 'MATCH p=(a)-[e:ARCHITECT_FOR]->(b)-[d:HAS_RISK]->(c) WHERE a.shortname="macdonb" RETURN nodes(p) AS n,relationships(p) AS m',
         params: {

        }
    }, function (err, results) {

        if (err) { throw err; }
        var result = results[0];
        if (!result) {
            console.log('No TechRisk found.');
        } else {
            console.log(results);
            console.log(results[0]);
            console.log(results[1]);
        }
    });
}

The code above produces the following JSON (with separators added to the chunks for readability) Produces these results:

- - - - console.log(results); - - - -

[ { n: [ [Object], [Object], [Object] ],
    m: [ [Object], [Object] ] },
  { n: [ [Object], [Object], [Object] ],
    m: [ [Object], [Object] ] },
  { n: [ [Object], [Object], [Object] ],
    m: [ [Object], [Object] ] },
  { n: [ [Object], [Object], [Object] ],
    m: [ [Object], [Object] ] },
  { n: [ [Object], [Object], [Object] ],
    m: [ [Object], [Object] ] } ]

- - - - console.log(results[0]); - - - -

{ n:
   [ Node { _id: 585, labels: [Object], properties: [Object] },
     Node { _id: 675, labels: [Object], properties: [Object] },
     Node { _id: 695, labels: [Object], properties: [Object] } ],
  m:
   [ Relationship {
       _id: 845,
       type: 'ARCHITECT_FOR',
       properties: [Object],
       _fromId: 585,
       _toId: 675 },
     Relationship {
       _id: 813,
       type: 'HAS_RISK',
       properties: [Object],
       _fromId: 675,
       _toId: 695 } ] }

- - - - console.log(results[1]); - - - -

{ n:
   [ Node { _id: 585, labels: [Object], properties: [Object] },
     Node { _id: 674, labels: [Object], properties: [Object] },
     Node { _id: 689, labels: [Object], properties: [Object] } ],
  m:
   [ Relationship {
       _id: 844,
       type: 'ARCHITECT_FOR',
       properties: [Object],
       _fromId: 585,
       _toId: 674 },
     Relationship {
       _id: 810,
       type: 'HAS_RISK',
       properties: [Object],
       _fromId: 674,
       _toId: 689 } ] }

The n: array is confounding me. I started ripping it apart manually (trying split and splice with strings and objects respectively) but I believe it must be accessible using a json parser. When I use the following as a test:

var tmpResult1 = JSON.stringify(result.n);

I get a great string representation of n:

[{"_id":585,"labels":["Person"],"properties":{"hrpno":"00061627","lastName":"MacDonald","title":"Consultant, IT Architecture","hrdno":"104134","shortname":"macdonb","role":"Systems Architect","displayName":"Bruce MacDonald","firstName":"Bruce"}},{"_id":650,"labels":["Application"],"properties":{"dateverified":"2016-01-19","name":"Portal - Loss Runs","aprmid":"aprm1249"}},{"_id":683,"labels":["TechRisk"],"properties":{"status":"Documented","riskid":"ABC-2012-082","dateEntered":"2012-06-29"}}]

The string is nice but when I try to reference the array with dots or brackets I get a lot of "undefined" errors.

I'm a little lost and about ready to take another day or two break from it. I've looked for tutorials on YouTube - "about 49,300 results" (!!!) and of the 30+ I've looked at they all deal with simple structures and use "Movies" as the example.

Again, thanks for reading this far! I appreciate any help or clues.

Upvotes: 5

Views: 2993

Answers (3)

Keyvan
Keyvan

Reputation: 873

I've written a library specifically for this purpose:

https://www.npmjs.com/package/parse-neo4j

It parses Neo4j's output and extracts only what's been returned in the query, see if it helps!

Neo4j's http endpoint produces result that contains complete query information.

parse-neo4j helps those who only want what they've returned in the query as normal JSON.

Upvotes: 4

Shanoor
Shanoor

Reputation: 13682

I think you're confused by the console.log() output, it's only a short representation, it doesn't always show the entirety of the object (for instance [Object] means there is an inner complex object). results is an object not a JSON string, do a console.log(typeof results); and it will output object.

You can use console.log(JSON.stringify(results, null, 3)); to display the entire object, it will help you to traverse the object by seeing exactly where the properties you need are (it's only for debug sake). Next, you don't need to parse or splice/split anything since result is a valid JS object, stringifiying it only makes things much harder. For example, try console.log(results[0].n[0].properties.lastName);, it should display MacDonald.

Upvotes: 1

Bruce MacDonald
Bruce MacDonald

Reputation: 288

After a good night's sleep I thought I would take another crack at this. I progressively walked through the array of objects of arrays of objects etc... and here's what I ended up with - Here is my new else condition...

EDIT: I forgot to mention that I ended up using the lodash library.

} else {
    var TechRisk = [];
    for ( var i = 0, len = results.length; i < len; ++i) {
        TechRisk.push(_.defaults(_.get((_.get(results[i], 'n')[0]), 'properties'),_.get((_.get(results[i], 'n')[1]), 'properties'),_.get((_.get(results[i], 'n')[2]), 'properties'),_.get((_.get(results[i], 'm')[0]), 'properties'),_.get((_.get(results[i], 'm')[1]), 'properties')));
    }
    res.status(200).send(TechRisk);
}

If anyone has a more elegant way to work through my group of nested objects, let me know. This is a bit of brute force and is very brittle (my Cypher query needs to utilize the params so I can pass in different users, etc).

For where I am in the development cycle it gets me moving forward.

Cheers!

Upvotes: 0

Related Questions