Search code examples
scalaneo4jcypheranormcypher

AnormCypher: How to get a complete path for a given node?


For a graph consisting of two groups of nodes:

n1 -> n2 -> n3 -> n4

and

n5 -> n6 -> n7

Created with commands:

CREATE (n1 { id:'n1' })-[:rel]->(n2 {id:'n2' })-[:rel]->(n3 { id:'n3' })-[:rel]->(n4 {id:'n4'})

CREATE (n5 { id:'n5' })-[:rel]->(n6 {id:'n6' })-[:rel]->(n7 { id:'n7' })

For both requests:

MATCH p = (n {id: 'n1'})-[*]-(m) RETURN nodes(p) as nodes;

MATCH p = (n {id: 'n1'})-[*]-(m) RETURN relationships(p) as rels ;

AnormCypher (http://anormcypher.org/) returns info related only to nodes n1 and n2, while Neo4J Web console returns a complete path.

How to get all nodes and relations for the complete path in AnormCypher?

Program that demonstrates this (at the end of this message) outputs:

ListBuffer(NeoNode(32,Map(id -> n1)), NeoNode(33,Map(id -> n2)))
Node: id=32 props=Map(id -> n1)
--Props keys:
----key: id val: n1
Node: id=33 props=Map(id -> n2)
--Props keys:
----key: id val: n2
ListBuffer(NeoRelationship(27,Map(),32,33))
Rel: id=27 start=32 end=33 props=Map()

Code:

object Simple {
   def main(args: Array[String]): Unit = {

Cypher("MATCH p = (n {id: 'n1'})-[*]-(m) RETURN nodes(p) as nodes;")().map { row =>

  println(row[Seq[org.anormcypher.NeoNode]]("nodes"))
  val nodes = row[Seq[org.anormcypher.NeoNode]]("nodes")

  nodes.map(n => {
    val props = n.props
    println("Node: id="+n.id+" props="+props)
    println("--Props keys: ")
    val x = props.keys
    props.keys.map( k=> println("----key: "+k+" val: "+props(k)))
    })
}

Cypher("MATCH p = (n {id: 'n1'})-[*]-(m) RETURN relationships(p) as rels ;")().map { row =>

  println(row[Seq[NeoRelationship]]("rels"))
  val rels = row[Seq[NeoRelationship]]("rels")
  rels.map(r => {
    val x = r.props
    println("Rel: id="+r.id+" start="+r.start+" end="+r.end+" props="+r.props)
  })
}

 }
}

Solution

  • The problem is your map function is creating a lazy stream, and you're not iterating over the rest of the stream. If you add .toList or .last to the end of your .map, forcing the iteration over the full stream, you should get the longer path results.

    For example:

    Cypher("MATCH p = (n {id: 'n1'})-[*]-(m) RETURN nodes(p) as nodes;")().map { row =>
      println(row[Seq[org.anormcypher.NeoNode]]("nodes"))
      val nodes = row[Seq[org.anormcypher.NeoNode]]("nodes")
    
      nodes.map(n => {
        val props = n.props
        println("Node: id="+n.id+" props="+props)
        println("--Props keys: ")
        val x = props.keys
        props.keys.map( k=> println("----key: "+k+" val: "+props(k)))
        })
    }.toList
    

    Alternatively, you could just use .foreach instead of .map, which does this for you.

    Update: Here's an example that has no return type:

    Cypher("MATCH p = (n {id: 'n1'})-[*]-(m) RETURN nodes(p) as nodes;")().foreach { row =>
      println(row[Seq[org.anormcypher.NeoNode]]("nodes"))
      val nodes = row[Seq[org.anormcypher.NeoNode]]("nodes")
    
      nodes.map(n => {
        val props = n.props
        println("Node: id="+n.id+" props="+props)
        println("--Props keys: ")
        val x = props.keys
        props.keys.map( k=> println("----key: "+k+" val: "+props(k)))
        })
    }