snowmantw
snowmantw

Reputation: 1621

How to solve the dilemma while handle JSON in Neo4j Cypher?

I've found that I can't use the standard JSON string in the Cypher query while I were writing a Node.js application:

var neo4j = require('neo4j')
   ,db = new neo4j.GraphDatabase('http://localhost:7474')
   ,enc_datum = JSON.stringify({id: 1, data: 'foo'})
   ,qstr  = ['MATCH (n %DATUM)'
            ,'RETURN n'
            ].join('\n')
          .replace('%DATUM', enc_datum)
db.query(qstr)

It would complain about the '"' character, because Cypher accept encoded object like this:

MATCH (n {id: 1, data: 'foo'})
RETURN n

Which is not what encoded with JSON:

var enc_datum = JSON.stringify({id: 1, data: 'foo'})
console.log(enc_datum)
// would be {"id":1,"data":"foo"}

The error messages show that Cypher, or the Neo4j module, doesn't accpet standard JSON because of the " character. It would complain that the next character after the { should be identifier or something else.

So I got stuck: either I must handle the JSON string with some nasty RegExpr before it got embedded in the query string, or I must invent a way to encode objects just for the tiny " character. I just want to ask if there're some more suitable solutions before I jump into these two tricky ways...

(I now solve this in test by using eval instead of JSON to eval my encoded data, while the string would be directly used in the Cypher query so I can't use JSON to stringify it. But I can't handle client encoded JSON in this way)

Upvotes: 1

Views: 1329

Answers (2)

Michael Hunger
Michael Hunger

Reputation: 41706

  1. Cypher doesn't use JSON it is a map format that looks a bit like JSON but doesn't use quotes for keys
  2. use parameters instead MATCH (n {props}) pass the actual parameters as values
  3. like this

    {"query","MATCH (n {props}) return n", "params": {"props":{"id":1,"data":"foo"}}}

Upvotes: 3

alex
alex

Reputation: 12275

MATCH (n {id: 1, data: 'foo'})

The format you seem to be using is JSON5. You can avoid double quotes with code like this:

var jju = require('jju')

jju.stringify({id: 1, data: 'foo'}, {quote:"'"}).replace(/"/g,'\\x22')
// result: "{id: 1, data: 'foo'}" (string)

jju.parse("{id: 1, data: 'foo'}")
// result: {id: 1, data: 'foo'} (object)

Please note two important things here:

  1. "quote" parameter ensures that module will always use single quotes to wrap strings
  2. replace() ensures that all double quotes will be encoded as \x22 if they happen to be in your input (i.e. data: 'foo"bar')

I don't know what other restrictions do that database have, maybe it's worth to encode it with base64 or something.

Upvotes: 3

Related Questions