0
votes

A portion of my neo4j graph represents objects, their values, and the attributes associated with those values. To use common programming syntax, I'm persisting something like the result of:

Object.Attribute = Value

where Object, Attribute and Value are all nodes, and they're linked by VALUE and ATTRIBUTE relationships like this:

Object-[:VALUE]->Value-[:ATTRIBUTE]->Attribute

To describe this with a specific example, the result of this code:

Object.Colour = 'Red'

would be persisted as:

Object-[:VALUE]->(Value { value:'Red' })-[:ATTRIBUTE]->(Attribute { name:'Colour' })

The problem occurs when I want to modify a persisted state like that above, and I wish to re-use existing Attribute (and ideally, Value) nodes - that is, I don't want to have multiple instances of the Attribute { name:'Colour' } node, I want to have a single instance that is related to each Value node instance.

The following Cypher query will go ahead and create new Value and Attribute nodes every time, regardless of whether identical nodes already exist:

    start o=node(something)
    create unique o-[:VALUE]->(v {value:'Green'})-[:ATTRIBUTE]->(a {name:'Colour'})
    return v;

The following will apparently recycle both Value and Attribute nodes, but of course won't work when the required Attribute doesn't exist (i.e. the first time it's used):

start o=node(something), a=node(something)
create unique o-[:VALUE]->(v {value:'Green'})-[:ATTRIBUTE]->a
where a.name = 'Colour'
return v;

The statement in the documentation that "create unique will always make the least change possible to the graph — if it can use parts of the existing graph, it will", doesn't appear to be completely true, and I don't understand why my query doesn't exhibit this behaviour.

How can I get the "recycling" effect of the latter query, combined with the creation on demand of the Attribute (and Value) when required like the former?

1

1 Answers

0
votes

The first problem is that you are building a property graph in a property graph. It's possible, but awkward and not always a good choice.

Your example: http://console.neo4j.org/r/evl77k

If understood you correctly, you want to be able to change the value node and re-use the same attribute node, right?

The problem is that in your second query, you ask Cypher to find value node with a different property than what is already in your graph. Cypher can't find such a node, and so creates one for you. It then tries to find an outgoing ATTRIBUTE relationship from the newly created node, and of course it doesn't find any. So it creates a new relationship and attribute for you.

If you want to keep using the same attribute node, you simply omit the property value from the value node, like so:

START  o=node(0) 
CREATE UNIQUE o-[:VALUE]->(v)-[:ATTRIBUTE]->(a {name:'Colour'}) 
SET    v.value = 'Green' 
RETURN v

This will find you Colour attribute node, and then set the property for you, instead of creating new paths every time.

Makes sense?

Andrés