So I know when you created nodes neo4j has a UUID for each node. I know you can access a particular node by that UUID by accessing the ID. For example:
START n=node(144)
RETURN n;
How would I get the last node that was created? I know I could show all nodes and then run the same command in anotehr query with the corresponding ID, but is there a way to do this quickly? Can I order nodes by id and limit by 1? Is there a simpler way? Either way I have not figured out how to do so through a simple cypher query.
Every time not guaranteed that a new node always has a larger id than all previously created nodes,
So Better way is to set created_at property which stores current time-stamp while creating node.
You can use timestamp() function to store current time stamp
Then,
Match (n)
Return n
Order by n.created_at desc
Limit 1
Please be aware that Neo4j's internal node id is not a UUID. Nor is it guaranteed that a new node always has a larger id than all previously created nodes. The node id is (multiplied with some constant) the offset of the node's location within a store file. Due to space reclaiming a new node might get a lower id number.
BIG FAT WARNING: Do not take any assumption on node ids.
Depending on your requirements you could organize all nodes into a linked list. There is one "magic" node having a specific label, e.g. References that has always a relationship to the latest created node:
CREATE (entryPoint:Reference {to:'latest'}) // create reference node
When a node from your domain is created, you need to take multiple actions:
remove the latest relationships if existing
create your node
connect your new node to the previously latest node
create the reference link
.
MATCH (entryPoint:Reference {to:'latest'})-[r:latest]->(latestNode)
CREATE (domainNode:Person {name:'Foo'}), // create your domain node
(domainNode)-[:previous]->(latestNode), // build up a linked list based on creation timepoint
(entryPoint)-[:latest]->(domainNode) // connect to reference node
DELETE r //delete old reference link
I finally found the answer. The ID() function will return the neo4j ID for a node:
Match (n)
Return n
Order by ID(n) desc
Limit 1;
Related
I want to delete a connected graph related to a particular node in a Neo4j database using Cypher. The use case is to delete a "start" node and all the nodes where a path to the start node exists. To limit the transaction the query has to be iterative and must not disconnect the connected graph.
Until now I am using this query:
OPTIONAL MATCH (start {indexed_prop: $PARAM})--(toDelete)
OPTIONAL MATCH (toDelete)--(toBind)
WHERE NOT(id(start ) = id(toBind)) AND NOT((start)--(toBind))
WITH start, collect(toBind) AS TO_BIND, toDelete limit 10000
DETACH DELETE toDelete
WITH start, TO_BIND
UNWIND TO_BIND AS b
CREATE (start)-[:HasToDelete]->(b)
And call it until deleted node is equal to 0.
Is there a better query for this ?
You could try a mark and delete approach, which is similar to how you would detach and delete the entire connnected graph with a variable match, but instead of DETACH DELETE you can apply a :TO_DELETE label.
Something like this (making up a label to use for the start node, as otherwise it has to comb the entire db looking for a node with the indexed param):
MATCH (start:StartNodeLabel {indexed_prop: $PARAM})-[*]-(toDelete)
SET toDelete:TO_DELETE
If that blows up your heap, you can run it multiple times, with the added predicate WHERE NOT toDelete:TO_DELETE before the SET, and using a combination of LIMIT and/or a limit on the depth of the variable-length relationship.
When you're sure you've labeled every connected node, then it's just a matter of deleting every node in the TO_DELETE label, and you can run that iteratively, or use APOC procedure apoc.periodic.commit() to handle that in batches.
I have a requirement to match two existing nodes with a specific Id and then create a relationship between these nodes.
Below is my cypher. But when I execute this , I always get no changes done .
MATCH(i:`Mechanical Component`)
where ID(i)=9912
with(i)
match(d:Features{name:"Mechanical Component"})
with(d)
where ID(d)=9934
MERGE (i)-[:FEATURES]->(d)
As Frank Pavageau said in the comments, you made an error in your query by not passing i with d in tha second WITHclause. Here is the corrected query you need:
MATCH(i:Mechanical Component)
where ID(i)=9912
with(i)
match(d:Features{name:"Mechanical Component"})
with(d,i)
where ID(d)=9934
MERGE (i)-[:FEATURES]->(d)
Keep in mind that using the internal id is really not recommended since it's generated and may change (see Should we use the Neo4J internal id?). You should probably use your own unique ID (with constraints) and match your node using this ID.
I have a Neo4J DB up and running with currently 2 Labels: Company and Person.
Each Company Node has a Property called old_id.
Each Person Node has a Property called company.
Now I want to establish a relation between each Company and each Person where old_id and company share the same value.
Already tried suggestions from: Find Nodes with the same properties in Neo4J and
Find Nodes with the same properties in Neo4J
following the first link I tried:
MATCH (p:Person)
MATCH (c:Company) WHERE p.company = c.old_id
CREATE (p)-[:BELONGS_TO]->(c)
resulting in no change at all and as suggested by the second link I tried:
START
p=node(*), c=node(*)
WHERE
HAS(p.company) AND HAS(c.old_id) AND p.company = c.old_id
CREATE (p)-[:BELONGS_TO]->(c)
RETURN p, c;
resulting in a runtime >36 hours. Now I had to abort the command without knowing if it would eventually have worked. Therefor I'd like to ask if its theoretically correct and I'm just impatient (the dataset is quite big tbh). Or if theres a more efficient way in doing it.
This simple console shows that your original query works as expected, assuming:
Your stated data model is correct
Your data actually has Person and Company nodes with matching company and old_id values, respectively.
Note that, in order to match, the values must be of the same type (e.g., both are strings, or both are integers, etc.).
So, check that #1 and #2 are true.
Depending on the size of your dataset you want to page it
create constraint on (c:Company) assert c.old_id is unique;
MATCH (p:Person)
WITH p SKIP 100000 LIMIT 100000
MATCH (c:Company) WHERE p.company = c.old_id
CREATE (p)-[:BELONGS_TO]->(c)
RETURN count(*);
Just increase the skip value from zero to your total number of people in 100k steps.
I am using neo4j for one of my project, there's a node which only has a single property as name, I want to get that node using ID, it already has a ID but when I use this code
MATCH (s:SKILLS{ID:65110}) return s
It returns nothing, heres my node
If the query is wrong then how do I query it using the number
MATCH (s)
WHERE ID(s) = 65110
RETURN s
The ID function gets you the id of a node or relationship. This is different from any property called id or ID that you create.
START should only be used when accessing legacy indexes. It is disabled in Cypher 2.2 3.2 and up.
Neo4j recommends using WHERE ID(n) = , and furthermore states that it will only require a single lookup (does not scan every node to find the matching ID)
WARNING
The answer below is incorrect. It is listed for reference only. See the updated answer above (quoted). The text below is kept for reference only
You can use WHERE ID(s) = 65110, but this will check the ID of every node in your database.
There is a more efficient way to do this:
START s=NODE(517) MATCH(s) RETURN s
you can say:
(n:User) where id(n) >=20 RETURN n
this will return all nodes of type User with node reference ID more than 20
I'm looking for a way to generate unique identifiers for all my nodes/relationships in Neo4j, based on an incrementing counter (not big long uuids).
The internal ids maintained by the Neo4j engine are known not to be reliable as outside references.
A solution that comes close is the code proposed in this question, but it doesn't work when a single CREATE clause creates multiple new nodes:
// get unique id
MERGE (id:UniqueId{name:'Person'})
ON CREATE SET id.count = 1
ON MATCH SET id.count = id.count + 1
WITH id.count AS uid
// create a new node attached to every existing :something node
MATCH (n:something)
CREATE (:somethingRelated {id:uid}) -[:rel]-> (n)
When there are multiple (n:something), every newly created (:somethingRelated) will share the same id. Is there some way around this, using only Cypher?
Try this to allocate a block of ids:
// collect nodes to connect
MATCH (n:Crew) WITH collect(n) AS nodes
MERGE (id:UniqueId { name:'Person' })
// reserve id-range
SET id.count = coalesce(id.count,0)+ size(nodes)
WITH nodes, id.count - size(nodes) AS base
// for each index
UNWIND range(0,size(nodes)-1) AS idx
// get node, compute id
WITH nodes[idx] AS n, base +idx AS id
CREATE (:SomethingRelated { uid:id })-[:rel]->(n)
From my point of view it's not possible to do that in Cypher.
I suggest you to write Java Extension for that, because your approach with Cypher would not work in concurrent environment. You are not able to secure uniqueness.
Could you please tell us more about your use case and why you don't to use UUID? - https://github.com/graphaware/neo4j-uuid
Based on your comment below I suggest to create ID's in your application.