How to get the Node name in Neo4J - neo4j

I am new to Neo4j and am referring to this tutorial.
I am not finding any answer on how to fetch the node name using CQL.
For example:
If I create two nodes like so:
CREATE (Dhawan:player{name: "Shikar Dhawan", YOB: 1985, POB: "Delhi"})
CREATE (Ind:Country {name: "India"})
and then build relationship at a later date using:
CREATE (Dhawan)-[r:BATSMAN_OF]->(Ind)
How do we know the node name: Dhawan or Ind?
Using:
MATCH (n) RETURN n
I am getting back the label name but not the node name!
How do I get all the details of an existing graph DB?

The thing you're calling "the node name" is actually a variable, and is only present for the duration of a single query (or less, if you don't include it in a WITH clause and it goes out of scope). It is never saved to the graph db, and is not persisted data.
In your example, you would only be able to use CREATE (Dhawan)-[r:BATSMAN_OF]->(Ind) (and have those variables refer to your previously created nodes) if the create was performed in the same query where those variables were previously bound (and still in scope).
Otherwise, this would create two new nodes, create the :BATSMAN_OF relationship between them, and bind those variables to the new nodes for the duration of their scope.

Related

Cypher: create node and relationship if not exists, else create relationship

I am trying to use neo to create a unified data dictionary across many datasets, since many of the columns are shared. I have one dictionary as a csv per dataset, with common columns in each. I am new to graph databases, but I think the pseudo code should look like this:
Create dataset node (single node with name and featues of dataset)
Upload data dictionary for dataset in step 1
If field node exists, create relationship between dataset node and existing field node.
If not exists, create field node and relationship between dataset node and field node.
Excluding step 1 which I am doing manually for each dataset node, here is what I have so far:
USING PERIODIC COMMIT LOAD CSV WITH HEADERS FROM "file:.csv" AS csvLine
MERGE (d:data {field: csvLine.Field, dtype: csvLine.Type, format: csvLine.Format})
ON CREATE SET d.field = csvLine.Field
ON MATCH SET d.field = csvLine.Field
CREATE (dataset)-[r:CONTAINS]->(d);
The results appear almost correct, only new fields are created, and the number of created relationships is equal to the number of fields in the uploaded dataset. However, the (dataset) node I created previously does not connect to the fields. Instead, label-less nodes are created and attach to all the fields in the new dataset. How can I properly connect the dataset node to the appropriate fields?
The problem is here: CREATE (dataset)-[r:CONTAINS]->(d)
dataset is a variable, and this the first time it's used in the query, so this CREATE will create a blank node, bind it to the dataset variable, then create the relationship to d.
Variables only last for the duration of a query (or less, if they are not carried in scope with the WITH clause), and are never persisted to the database. If you previously created some node in a different query with the dataset variable, then that variable went out of scope when the query ended. If you want to refer to that same node again, you will need to match to that node in this query.

Create atmost one relationship for newly created node with existing node based on some property

My application receive stream of data which I need to persist in graph DB. With this data , I am first creating nodes in neo4j db in batches (of 1000) and just after that I am trying to find out matching node in existing data to link it.
MATCH(new:EVENT) where new.uniqueId in [NEWLY CREATED NODES UNIQUE ID]
MATCH (existing:EVENT) where new.myprop = existing.myprop and new.uniqueId <> exising.uniqueID
CREATE (new)-[:LINKED]-(existing)
My problem is, if for a node there are more than one matching existing node than i want to create relationship with just one existing node. My current above query will create relationship with all matching nodes.
is there any efficient way of doing it as number of existing node could be huge ie approx 300M.
Node: I have index created on myprop and uniqueId field
As #InverseFalcon's answer states, you can use aggregation to collect the existing nodes for each distinct new, and take the first in each collection.
For better performance, you should always PROFILE a query to see what can be improved. For example, after doing that with some sample data on my neo4j installation, I saw that: the index was not automatically being used when finding new, and the new.uniqueId <> exising.uniqueId test was causing DB hits. This query fixes both issues, and should have better performance:
MATCH(new:EVENT)
USING INDEX new:EVENT(uniqueId)
WHERE new.uniqueId in [NEWLY CREATED NODES UNIQUE ID]
MATCH (existing:EVENT)
WHERE new.myprop = existing.myprop AND new <> existing
WITH new, COLLECT(existing)[0] AS e
CREATE (new)-[:LINKED]->(e);
It uses USING INDEX to provide a hint to use the index. Also, since uniqueId is supposed to be unique, it just compares the new and existing nodes directly to see if they are the same node.
To ensure that the uniqueness is actually enforced by neo4j, you should create a uniqueness constraint:
CREATE CONSTRAINT ON (e:EVENT) ASSERT e.uniqueId IS UNIQUE;
You can collect the existing node matches per new node and just grab the first:
MATCH(new:EVENT) where new.uniqueId in [NEWLY CREATED NODES UNIQUE ID]
MATCH (existing:EVENT) where new.myprop = existing.myprop and new.uniqueId <> exising.uniqueID
WITH new, head(collect(existing)) as existing
CREATE (new)-[:LINKED]-(existing)

Create a node in neo4j if not present.

Is it possible to create a node only if it not present in the graph.
Example node A is already present, So my query should Check if node A is already present if not create a node. I don't want to use constraint here.
It's needed for load data from mysql without duplicate entries.
Yes, you want the MERGE keyword:
MERGE either matches existing nodes and binds them, or it creates new data and binds that. It’s like a combination of MATCH and CREATE that additionally allows you to specify what happens if the data was matched or created.
For example, you can specify that the graph must contain a node for a user with a certain name. If there isn’t a node with the correct name, a new node will be created and its name property set.
Use whichever columns that make your rows in MySQL unique.
http://neo4j.com/docs/stable/query-merge.html

Dynamic Nodes and relationship creation in Neo4j

I am storing Hierarchy data in Neo4j. I want to store history of the Node. Consider I have a label called GROUP and the earlier name was "MARKETING" now it has been changed to "MARKET123". So i want to create a new node where the name will be MARKET123 and the create a relationship with other connected node same as for the older node named "MARKETING"...
But all this i want to do dynamically instead of passing the other Nodes name and the relationship value in the cypher query.
Please suggest me how it can be done.
You can add versioning to your graph nodes.
Here is a graph gist about time-based versioning that you may adapt to your needs.
http://www.neo4j.org/graphgist?608bf0701e3306a23e77

neo4j not reusing existing vertex in cypher create unique query

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?
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

Resources