Search code examples
rubyjsonneo4jsinatraneography

Neo4j JSON Objects to Elements


I'm not sure that I'm using the correct terminology, so feel free to correct it when necessary. I (think) I have JSON objects that I'm attempting to convert into an array of elements.

I'm using Neography in Ruby to query a Neo4j database, and when I receive the results back, I need them to look like this:

["apple","orange","pear"]

However, they look like this:

[["apple"],["orange"],["pear"]]

The Ruby I'm using to create this is:

cypher = "MATCH (n:Person) WHERE n.name =~ '(?i).*#{term}.*' RETURN n.name"
results = neo.execute_query(cypher)["data"].to_json
puts results
results

I'd read here (How to Remove Square bracket from JSON) to try parsing the JSON, and getting the first element.

cypher = "MATCH (n:Person) WHERE n.name =~ '(?i).*#{term}.*' RETURN n.name"
results = neo.execute_query(cypher)["data"].to_json  
results = JSON.parse(results)
puts results
results.to_s # deals with Sinatra not being able to display a hash?

But gotten the same double-bracket results.


Solution

  • I'd suggest looking into the Neo4j.rb project (the neo4j-core and neo4j gems). Full disclosure: I'm one of the maintainers ;). With neo4j-core you might do:

    neo4j_session = Neo4j::Session.open(:server_db, 'http://neo4j:password@localhost:7474')
    cypher = "MATCH (n:Person) WHERE n.name =~ '(?i).*#{term}.*' RETURN n.name AS name"
    results = neo4j_session.query(cypher).map(&:name)
    

    You should be using parameters in general, though, to prevent injection attacks:

    cypher = "MATCH (n:Person) WHERE n.name =~ {regex} RETURN n.name AS name"
    results = neo4j_session.query(cypher, regex: "(?i).*#{term}.*").map(&:name)
    

    You can also use the Query API which will make params for you and also convert Ruby regular expressions to Cypher syntax:

    results = neo4j_session.query.match(n: :Person).where(n: {name: /#{term}/i}).pluck('n.name')
    

    If you use ActiveNode from the neo4j gem it's even simpler:

    class Person
      include Neo4j::ActiveNode
    
      property :name, type: String
    end
    
    Person.where(name: /#{term}/i).pluck(:name)
    

    You could even make a search method on the Person model to do that for you:

    class Person
      include Neo4j::ActiveNode
    
      property :name, type: String
    
      def search(term)
        all.where(name: /#{term}/i)
      end
    end
    
    Person.search(term).pluck(:name)