diff --git a/modules/ROOT/images/ann-friends-mark.svg b/modules/ROOT/images/ann-friends-mark.svg new file mode 100644 index 00000000..f05549a0 --- /dev/null +++ b/modules/ROOT/images/ann-friends-mark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/ROOT/images/cypher_graph_mergeFriend-arr.svg b/modules/ROOT/images/cypher_graph_mergeFriend-arr.svg deleted file mode 100644 index c3451220..00000000 --- a/modules/ROOT/images/cypher_graph_mergeFriend-arr.svg +++ /dev/null @@ -1,3 +0,0 @@ -Personname:Mark \ No newline at end of file diff --git a/modules/ROOT/images/cypher_graph_mergeFriendRel-arr.svg b/modules/ROOT/images/cypher_graph_mergeFriendRel-arr.svg deleted file mode 100644 index cf952fc4..00000000 --- a/modules/ROOT/images/cypher_graph_mergeFriendRel-arr.svg +++ /dev/null @@ -1,3 +0,0 @@ -:IS_FRIENDS_WITHPersonname:JenniferPersonname:Mark \ No newline at end of file diff --git a/modules/ROOT/images/cypher_graph_mergeFriendRel.jpg b/modules/ROOT/images/cypher_graph_mergeFriendRel.jpg deleted file mode 100644 index 478ce657..00000000 Binary files a/modules/ROOT/images/cypher_graph_mergeFriendRel.jpg and /dev/null differ diff --git a/modules/ROOT/images/update-graph.svg b/modules/ROOT/images/update-graph.svg new file mode 100644 index 00000000..d9851da4 --- /dev/null +++ b/modules/ROOT/images/update-graph.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/ROOT/pages/cypher/updating.adoc b/modules/ROOT/pages/cypher/updating.adoc index 57676da5..dbab8e08 100644 --- a/modules/ROOT/pages/cypher/updating.adoc +++ b/modules/ROOT/pages/cypher/updating.adoc @@ -1,6 +1,6 @@ -= Updating the data += Updating the graph :tags: cypher, queries, graph-queries, insert-create, update, delete, merge -:description: Building on the Cypher Basics I guide, this guide covers more introductory concepts of Cypher, Neo4j's graph query language. Upon finishing this guide, you should be able to read and write Cypher queries for standard CRUD operations. +:description: This guide explains how to update data that already exists in a graph, using Cypher. :page-newsletter: true :page-ad-overline-link: https://graphacademy.neo4j.com/?ref=guides :page-ad-overline: Neo4j GraphAcademy @@ -10,27 +10,16 @@ :page-ad-underline-role: button :page-ad-underline: Learn more -Earlier you learned how to represent nodes, relationships, labels, properties, and patterns in Cypher. -This section adds another level to your knowledge by introducing how to update and delete data with Cypher. +This tutorial shows how to update information in the graph by changing, removing, and adding nodes, relationships, and properties. +It also addresses how to avoid duplication. -While these are the standard CRUD (create, update, and delete) operations, some things function a bit differently in a graph than in other types of databases. -You will probably recognize some of the similarities and differences as we go along. +== Create the dataset -[[cypher-update]] -== Updating data with Cypher - -You may already have a node or relationship in the data, but you want to modify its properties. -You can do this by matching the pattern you want to find and using the `SET` keyword to add, remove, or update properties. - -We continue to use the following dataset: - -.Graph: people, companies they work at, and technologies they like -image::people-technologies-graph-arr.svg[role="popup-link"] - -To create the aforementioned graph, run the Cypher query: +After you link:https://neo4j.com/product/auradb/?ref=docs-nav-get-started[create a free Aura instance], use the "Connect" button and select "Query". +In the Cypher editor, copy and paste the following Cypher and execute the query: [source, cypher] ----- +-- CREATE (diana:Person {name: "Diana"}) CREATE (melissa:Person {name: "Melissa", twitter: "@melissa"}) CREATE (dan:Person {name: "Dan", twitter: "@dan", yearsExperience: 6}) @@ -65,286 +54,271 @@ CREATE (ann)<-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]->(mark) CREATE (john)-[:LIKES]->(dev)<-[:LIKES]-(ann)-[:IS_FRIENDS_WITH]->(dan)-[:WORKS_FOR]->(abc) CREATE (ann)-[:WORKS_FOR]->(abc) CREATE (a)<-[:WORKS_FOR]-(melissa)-[:LIKES]->(graphs)<-[:LIKES]-(diana) ----- +-- + +You should now have a graph with 20 nodes, 31 relationships, 28 properties, and 20 labels. +image::update-graph.svg[All nodes added to the graph,width=500] -Using the above example dataset thus far, you could update Jennifer's node to add her birthdate. -The next Cypher statement shows how to do this. +== Add a property to a node -. First, you need to find the existing node for Jennifer. -. Next, use `SET` to create the new property (with syntax `variable.property`) and set its value. -. Finally, you can return Jennifer's node to ensure that the information was updated correctly. +If you want to add a birthday for the person named Jennifer, you can add this information as a _property_ with this query: [source, cypher] ----- +-- MATCH (p:Person {name: 'Jennifer'}) SET p.birthdate = date('1980-01-01') RETURN p ----- +-- -*Query result:* +This query does the following: -[queryresult] +. Find Jennifer's node with the `MATCH` clause. +. Use `SET` to create the new property `birthday` (with syntax `variable.property`) and set its value. +. Use `RETURN` to return Jennifer's node and so you can ensure that the information was updated correctly. ----- -Set Properties: 1 -Rows: 1 - -+------------------------------------------------------+ -| p | -+------------------------------------------------------+ -|(Person: {birthdate: '1980-01-01', name: 'Jennifer'}) | -+------------------------------------------------------+ ----- +This is the tabular result: +[role="queryresult",options="header,footer",cols="1* Temporal functions^]. -==== +| (:Person {twitter: "@jennifer", birthdate: 1980-01-01, name: "Jennifer", yearsExperience: 5}) -If you want to change Jennifer's birthdate, you can use the same query above to find Jennifer's node again and put a different date in the `SET` clause. +1+d|Rows: 1 +|=== -You are able also update Jennifer's `WORKS_FOR` relationship with the `Company` node to include the year that she started working there. -To do this, you can use similar syntax as above for updating nodes. +== Update a property + +To change Jennifer's birthdate, you can use the same query from the previous example to find Jennifer's node again, and change the property value by adding a different date with the `SET` clause: [source, cypher] ----- -MATCH (:Person {name: 'Jennifer'})-[rel:WORKS_FOR]-(:Company {name: 'Neo4j'}) -SET rel.startYear = date({year: 2018}) -RETURN rel ----- +-- +MATCH (p:Person {name: 'Jennifer'}) +SET p.birthdate = date('1980-01-02') +RETURN p +-- +This is the tabular result: -*Query result:* +[role="queryresult",options="header,footer",cols="1*(m:Person {name: 'Mark'}) -DELETE r +MATCH (:Person {name: 'Jennifer'})-[rel:WORKS_FOR]-(:Company {name: 'Neo4j'}) +SET rel.startYear = date({year: 2018}) +RETURN rel ---- -*Query result:* +This is the result: -[queryresult] ----- -+-----------------------------------------+ -| Deleted Relationships: 1 | -| Rows: 0 | -+-----------------------------------------+ ----- +[role="queryresult",options="header,footer",cols="1*(m) -RETURN j, r, m ----- +[source,cypher] +-- +CREATE (a:Person {name: 'Ann'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'}) +RETURN a, r, m +-- -Notice that here `MATCH` is used to find both Mark's node and Jennifer's node before we use `MERGE` to find or create the relationship between them. +The result is that you duplicate Ann's node and create a new Mark node (since it was removed in xref:cypher/updating.adoc#_delete_a_node_and_its_relationships[the previous step]) and add a new `IS_FRIENDS_WITH` relationship between them. +You get the following message confirming it: "Created 2 nodes, created 1 relationship, set 2 properties, added 2 labels". -Why do we not use a single statement? +If you use `MERGE` instead: -`MERGE` looks for an entire pattern that you specify to see whether to return an existing one or create it new. -If the entire pattern (nodes, relationships, and any specified properties) does not exist, Cypher creates it. +[source,cypher] +-- +MERGE (j:Person {name: 'Ann'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'}) +RETURN j, r, m +-- -Cypher never produces a partial mix of matching and creating within a pattern. -To avoid a mix of match and create, you need to match any existing elements of your pattern first before doing a merge on any elements you might want to create, just as we did in the statement above. +The result is more duplication. +`MERGE` tries to match the *entire* pattern, and if it doesn't exist, it is created. -image::cypher_graph_mergeFriendRel-arr.svg[role="popup-link", width=600] +Even though the graph already has Ann and Mark's nodes, the pattern `(Ann)-[:IS_FRIENDS_WITH]->(Mark)` doesn't exist, so all elements are created anew. [NOTE] ==== -Just for reference, the Cypher statement that causes duplicates is below. -Since this pattern (`Jennifer IS_FRIENDS_WITH Mark`) does not exist in the database, Cypher creates the entire pattern new -- both nodes, as well as the relationship between them. +If you created the previous duplication, you don't need to fix it before proceeding with the tutorial. +However, if you didn't do it, you need to create a new node for Mark, as it was removed in xref:cypher/updating.adoc#_delete_a_node_and_its_relationships[the previous step]. +You can do it using either `CREATE` or `MERGE`. +==== + +In order to create the new relationship, without duplications, you need to first `MATCH` Ann and Mark's nodes and then `MERGE` (or `CREATE`) the relationship: [source, cypher] ---- -//this statement will create duplicate nodes for Mark and Jennifer -MERGE (j:Person {name: 'Jennifer'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'}) -RETURN j, r, m +MATCH (a:Person {name: 'Ann'}) +MATCH (m:Person {name: 'Mark'}) +MERGE (a)-[r:IS_FRIENDS_WITH]->(m) +RETURN a, r, m ---- -==== -=== Handling _MERGE_ criteria +image::ann-friends-mark.svg[Ann and Mark's nodes are connected through a is friends with relationship,width=400,role=popup] -Perhaps you want to use `MERGE` to ensure you do not create duplicates, but you want to initialize certain properties if the pattern is created and update other properties if it is only matched. -In this case, you can use `ON CREATE` or `ON MATCH` with the `SET` keyword to handle these situations. +== Conclusion -Let us look at an example. +In this tutorial, you have seen how to update nodes, relationships, and properties. +You have also seen how to delete data from the graph as well as how to avoid duplication when adding new data. -[source, cypher] ----- -MERGE (m:Person {name: 'Mark'})-[r:IS_FRIENDS_WITH]-(j:Person {name:'Jennifer'}) - ON CREATE SET r.since = date('2018-03-01') - ON MATCH SET r.updated = date() -RETURN m, r, j ----- +== Keep learning -[[cypher-resources]] -== Resources +If you want to learn more about how to update your graph and find the best way to model your data, refer to: -* link:https://neo4j.com/docs/cypher-manual/current/clauses/create/[Neo4j Cypher Manual: CREATE^] -* link:https://neo4j.com/docs/cypher-manual/current/clauses/set/[Neo4j Cypher Manual: SET^] -* link:https://neo4j.com/docs/cypher-manual/current/clauses/remove/[Neo4j Cypher Manual: REMOVE^] -* link:https://neo4j.com/docs/cypher-manual/current/clauses/delete/[Neo4j Cypher Manual: DELETE^] -* link:https://neo4j.com/docs/cypher-manual/current/clauses/merge/[Neo4j Cypher Manual: MERGE^] -* link:https://neo4j.com/docs/cypher-manual/current/clauses/merge/#query-merge-on-create-on-match[Neo4j Cypher Manual: ON CREATE/ON MATCH^] +* xref:data-modeling/index.adoc[*Data modeling*] -> A complete section on how to get started with data modeling through tutorials and reference material. \ No newline at end of file