Unrequested nodes returned by official drivers .graph() method

I am encountering an issue ("issue " feels a bit strong, "situation" maybe better) whereby the .graph() method on neo4j.work.result.Result objects returns nodes that were not requested as part of the Cypher query I submit through the driver.

  • Neo4j version: Enterprise 4.2.6
  • Neo4j Mode: Single instance
  • Driver version: Python neo4j driver 4.2.1
  • Operating system: Windows 10

For example, if I:

  • create a very simple graph of 2 nodes connected by 1 edge,
  • request in return only one of the nodes, along with the edge

Then I see the expected (requested) edge, the expected (requested) node, but also the unrequested/unexpected node in the output of output.graph().

Reproducible example:

from neo4j import GraphDatabase

db = GraphDatabase.driver(
    "bolt://127.0.0.1:7687",
    auth = ("neo4j", "neo4j")
)

sesh = db.session(database = "reprex")

output = sesh.run(
    '''
    create (a :test {Name: "Node1"})
    create (b :test {Name: "Node2"})
    create (a)-[c :CONNECTED_TO]->(b)
    return a, c
    '''
    )
graph = output.graph()
[n for n in graph.nodes]

Output:

[<Node id=0 labels=frozenset({'test'}) properties={'Name': 'Node1'}>, <Node id=1 labels=frozenset() properties={}>]

I'm assuming the "extra" node in the graph() output is coming as it's the "other end" of the relationship that I have requested, as I see it in the .values() output for that relationship:

>>> output.values()
[[<Node id=0 labels=frozenset({'test'}) properties={'Name': 'Node1'}>, <Relationship id=0 nodes=(<Node id=0 labels=frozenset({'test'}) properties={'Name': 'Node1'}>, <Node id=1 labels=frozenset() properties={}>) type='CONNECTED_TO' properties={}>]]

This makes sense to me on some level, as the relationship is defined between two nodes (so does it really "exist" from a theoretical perspective without (at least a reference to) both nodes it connects?).

However in this instance I'm not sure I would expect to see the unexpected/unrequested node as a (Python) object in the output of .graph().

Not sure if this is a bug, or if my/our expectations are just off slightly. It has some downstream implications on our work (we may want to select a node, a relationship, and not get the other unrequested node(s) that relationship links to) and whilst we have some workarounds (e.g. I think we can safely drop nodes from the .graph() output that don't have a label), but I wondered if there was something obvious I was missing here, if this is unexpected behaviour, and/or what others thought of it?

Thanks in advance for any thoughts.

Yes, it is working as expected, you asked for one node and a relationship (which itself must include two nodes).

There are a few ways to receive the data in python. I'm also using graph.nodes and graph.relationships, but I'm using it specifically for the reason you mention.

For any graph query (queries that return some/any assortment of nodes and relationships) this approach provides a simple list of unique nodes, and relationships from the results.

Which is, for example much easier to send into cytoscape.js, and all without writing a lot of code to unpack the usual complex return results... (which when combined with a dynamic query builder can change on every query)

Reference: https://neo4j.com/docs/api/python-driver/current/api.html#graph-data-types

Thanks Joel.

Suspected as much, this was a (rare-ish) edge case for us and I think we have a workaround, so this was more of a query than a problem.

Either way, appreciate the response.