Daniel Davies
Daniel Davies

Reputation: 158

Javascript Neo4j Driver Json parse express api

This may be a non-issue however I can't help but feel like there is a better way to do what I am trying to achieve.

I am writing an API in Express with my data stored in a neo4j database. I am using the official neo4j-driver to interface with neo4j which is running locally. When I run a query eg :

session
    .run(`MATCH (foo:FamilyMember)-[:HAS_SISTER]->(sister:FamilyMember)
    WHERE foo.firstName = 'bar'
    RETURN sister.firstName AS Name, sister.lastName AS Surname
    `)
    .then(res => {
        console.log(res);
    })

Neo4j returns a response object with a lot of information about the request:

{
  records: [
    Record {
      keys: [Array],
      length: 2,
      _fields: [Array],
      _fieldLookup: [Object]
    },
    Record {
      keys: [Array],
      length: 2,
      _fields: [Array],
      _fieldLookup: [Object]
    },
    Record {
      keys: [Array],
      length: 2,
      _fields: [Array],
      _fieldLookup: [Object]
    },
    Record {
      keys: [Array],
      length: 2,
      _fields: [Array],
      _fieldLookup: [Object]
    }
  ],
  summary: ResultSummary {
    query: {
      text: 'MATCH (foo:FamilyMember)-[:HAS_SISTER]->(sister:FamilyMember)\n' +
        "    WHERE foo.firstName = 'bar'\n" +
        '    RETURN sister.firstName AS Name, sister.lastName AS Surname\n' +
        '    ',
      parameters: {}
    },
    queryType: 'r',
    counters: QueryStatistics { _stats: [Object], _systemUpdates: 0 },
    updateStatistics: QueryStatistics { _stats: [Object], _systemUpdates: 0 },
    plan: false,
    profile: false,
    notifications: [],
    server: ServerInfo {
      address: 'localhost:7687',
      version: 'Neo4j/4.2.1',
      protocolVersion: 4.2
    },
    resultConsumedAfter: Integer { low: 0, high: 0 },
    resultAvailableAfter: Integer { low: 4, high: 0 },
    database: { name: 'neo4j' }
  }
}

This is a pain when really I what I want is either the actual response data as an array of objects or an error message if something fails.

I wrote this parse method to generate an array of Javascript object's with the data returned from the query:

function parseNeo4jResponseJSON(res) {
    return results = res.records.reduce( (array, currentRecord) => {
        const record = currentRecord.keys.reduce( (obj, key, index) => {
            obj[key] = currentRecord._fields[index]
            return obj
        }, {})
        array.push(record);
        return array;
    },[])
};

This works and now when I console log the query response through my parser I get it in the format I want eg:

[
  { Name: 'foo', Surname: 'bar' },
  { Name: 'foo2', Surname: 'bar2' },
  ...
]

Is this approach going to cause me problems down the line? Is there a better way to get a javascript object from the response? I am pretty new to neo4j. Apologies if the answer is obvious.

Upvotes: 1

Views: 597

Answers (1)

fbiville
fbiville

Reputation: 8960

Based on the existing examples, what about:

session
    .readTransaction((tx) => 
       tx.run(`MATCH (foo:FamilyMember)-[:HAS_SISTER]->(sister:FamilyMember)
               WHERE foo.firstName = 'bar'
               RETURN sister.firstName AS Name, sister.lastName AS Surname`)
    )
    .then(results => results.records.map((record) => {
       return {
              Name: record.get('Name'),
              Surname: record.get('Surname')
       }
    })

You could keep session.run, but the session.{read,write}Transaction variants are usually recommended because they work in every environment (where session.run may sometimes fail in a cluster environment).

Please also make sure to use a dictionary of parameters (2nd argument of tx.run) instead of using string interpolation, if your query needs to be parameterized. If the value of foo.firstName comes from a variable (let's say someFirstName), the tx.run would become:

tx.run("MATCH (foo:FamilyMember)-[:HAS_SISTER]->(sister:FamilyMember)
               WHERE foo.firstName = $firstName
               RETURN sister.firstName AS Name, sister.lastName AS Surname",
       {firstName: someFirstName})

Upvotes: 1

Related Questions