Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to add a temporary property to a neo4j node for return only?

Tags:

neo4j

cypher

I have been using cypher and neo4j for a while now, and I keep running into a similar problem again and again.

I would like to be able to add a "temporary" property to a node thats exists only in the returned data and is not persisted to the Neo4j database.

For example the current problem I am working on is given an N-ary tree structure in the graph database, I would like to return the children of a specific node, and an informational boolean letting me know weather those children have children.

The query to get this information is simple enough:

MATCH (parent:Item { guid: "Identifier here" })-[:HASCHILD]->(child:Item)
OPTIONAL MATCH (child)-[:HASCHILD]->(grandchild:Item)
WITH parent, child, LENGTH(COLLECT(grandchild)) > 0 AS has_children

Now I have the parent, child and a boolean letting me know weather there are further children.

What I would like to be able to do next is set the has_children boolean as a property on the child nodes, but just for returning the query, I don't need the property persisted.

I know there is are some solutions to get what I am looking for but none of them are specifically what I am looking for.

1) I could create a temporary node: (Continued from above query)

...
WITH parent, child, LENGTH(COLLECT(grandchild)) > 0 AS haschildren,
{
    childkey1: child.childkey1,
    childkey2: child.childkey2,
    ...
    has_children: haschildren
} AS tempnode
RETURN parent, tempnode

This solution is not great, you have to know the exact node type and all the properties of the node you are dealing with, it will not work in the general case.

2) I could SET and REMOVE the boolean, temporarily persisting it to the database (as described in Neo4J create temp variable within Cypher).

This is not great as it will cause multiple db writes (for add and remove). Also, it is not as dynamic as option 1 as it would only be able to handle simple types. (Option 1 can handle more complex cases, like adding a collection of nodes instead of a simple boolean).

As far as I know, these are the only options when it comes to temporary return data. I'm wondering am I missing any thing? Is it possible to make this more simple or dynamic?

Something along the lines of

 WITH parent, child, LENGTH(COLLECT(grandchild)) > 0 AS haschildren,
 TEMPSET child.has_children = haschildren

Please note that I have simplified the examples given a little. I have run into this issue multiple times in different contexts in neo4j. Most times I either go with option 1, or build the correct structure by post-processing on the application side once the query returns.

Is there a better way?

like image 965
Dalaigh88 Avatar asked Aug 23 '17 10:08

Dalaigh88


1 Answers

You can try returning a map projection. Take a look in this example:

// Creating a sample node    
CREATE (:Person {name:'Jon', id: 1})

Returning the projection with a extra boolean:

MATCH (p:Person {id:1})
WITH p, true AS has_children
RETURN p{.*, has_children:has_children}

The result:

╒═════════════════════════════════════════╕
│"p"                                      │
╞═════════════════════════════════════════╡
│{"id":1,"name":"Jon","has_children":true}│
└─────────────────────────────────────────┘

The above query is returning all properties of p node with an extra boolean.

like image 91
Bruno Peres Avatar answered Oct 07 '22 14:10

Bruno Peres