cancel
Showing results forΒ 
Search instead forΒ 
Did you mean:Β 

Using 'WITH' in JS Driver to unpack JSON up to Aura server

mikeM
Node Link

Hi all,

So I have an Aura pro server and want to upload a block of JSON data we're generating up to it. My little Node app, whilst generating this JSON, holds it in state, so I figured it would be simple enough to use the JS driver to send that up to the server. The query works within the browser, using the same data and command, but I get:

Neo4jError: Invalid input '[': expected "+" or "-" (line 1, column 6 (offset: 5))
"WITH [object Object],[object Object], ...

by using either writeTransaction or run using the JS driver.

Is there an inherent issue with using a 'WITH' statement with the JS driver.

The statement looks like this:

const writeQuery = `WITH ${serviceMapJson} AS objects
        UNWIND objects as service
        call apoc.create.node([service.type],
        {name:service.name, language:service.language, ... other fields listed})
        yield node
        return node`;

const writeResult = await session.writeTransaction((tx) => tx.run(writeQuery));

Is there a better way of doing this with static JSON? Aura seems to make it difficult to get JSON from a path since you can't upload to the server and things like pre-signed links in S3 don't work, so I went down this more direct route of passing the JSON in the query.

Also, I didn't want to have to iterate over the JSON object in the script and make several hundred individual create requests.

Any help appreciated, thanks.

p.s. Googling for 'WITH' statement Neo4j js driver is particularly problematic - 'with' being a fairly common word an' all πŸ™‚

1 ACCEPTED SOLUTION

You'd be better off passing the object as a parameter in the second parameter, like this:

const writeQuery = `
        UNWIND $serviceMapJson as service
        call apoc.create.node([service.type],
        {name:service.name, language:service.language, ... other fields listed})
        yield node
        return node`;

const writeResult = await session.writeTransaction((tx) => tx.run(writeQuery, { serviceMapJson }));

That way you don't need to worry about quotes, serialising/stringifying. It's also considered best practice to avoid injection when you come to processing inputs in a user-facing application and avoids re-planning the query before execution which adds a few hundred milliseconds to the query time.

One caveat you may need to account for with the JS driver is converting JavaScript integers into Neo4j integers. By default, these will be converted by the driver into floats to avoid loss, you can read more here.

If you are interested, you can learn more in the Building Neo4j Applications with Node.js course on GraphAcademy.

View solution in original post

4 REPLIES 4

glilienfield
Ninja
Ninja

I am not familiar with the ${serviceMapJson} syntax. Should this be $serviceMapJson instead?

Thanks for the reply glilienfield.

That's a NodeJS variable rather than a Cypher param. I should have put above the code snippet to make that clear:

const serviceMapJson = JSON.parse(jsonString);

You'd be better off passing the object as a parameter in the second parameter, like this:

const writeQuery = `
        UNWIND $serviceMapJson as service
        call apoc.create.node([service.type],
        {name:service.name, language:service.language, ... other fields listed})
        yield node
        return node`;

const writeResult = await session.writeTransaction((tx) => tx.run(writeQuery, { serviceMapJson }));

That way you don't need to worry about quotes, serialising/stringifying. It's also considered best practice to avoid injection when you come to processing inputs in a user-facing application and avoids re-planning the query before execution which adds a few hundred milliseconds to the query time.

One caveat you may need to account for with the JS driver is converting JavaScript integers into Neo4j integers. By default, these will be converted by the driver into floats to avoid loss, you can read more here.

If you are interested, you can learn more in the Building Neo4j Applications with Node.js course on GraphAcademy.

Thanks Adam, that's solved the issue. Feeding the data in as a parameter to the call rather than as part of the writeQuery worked a treat.

Much appreciated.