Getting started with Cypher and RedisGraph / Part II
Tags: cypher, redisgraph, graph, redis
Published: 2023-05-19 08:58:00

In the first post of this series we looked at what a Graph DB is and why should you use one.
Today we'll learn what is Cypher start querying the graph!

## What is Cypher
Cypher it's a declarative query language, developed internally by Neo4j since 2011.
There is an ongoing standardization process (OpenCypher) to make Cypher an open standard.
Cypher let's you easily retrieve data from the graph. It's one of the simplest query language to learn; its syntax is constructed in a way that helps visualize relationship between nodes

## RedisInsight
We will be running queries in RedisInsight. If you've read the previous post of this series, you should know how to run a docker based installation of Redis.
After launching `docker compose up -d`, point your browser to http://localhost:8001 , RedisInsight should welcome you. Accept the EULA and you will be redirected to RedisInsight dashboard.
Next click on the "Workbench" tab (the third icon in the side menu on the left).
The upper right pane of this new screen is where you'll write all the queries.

## Adding nodes and edges
Now that both Redis and RedisInsight are up & running, let's create a new graph and add one node to it:
```cypher
GRAPH.QUERY Social "CREATE (:Person {name: 'Laura Phillips', age: 32})"
```
Every query is prepended by `GRAPH.QUERY` and the graph name.
Now click the green arrow to the right or press `Ctrl + Enter`.

The output should be similar to this:

![after first CREATE](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9409d6edagd1mdbu0v6.png)

The first time we create e node in a non-existent graph, RedisGraph will create the graph for us.
So we've just created a new graph called "Social" and added one node of type "Person".
`name` and `age` are properties that we add to the node. RedisGrap automatically add another property to each node: the unique `id`.

We can add more nodes in bulk:
```cypher
GRAPH.QUERY Social "CREATE (:Person {name: 'Diana Hendrickson', age: 31}), (:Person {name: 'Susan Hendrickson', age: 29}), (:Person {name: 'Peter Steinmetz', age: 30}), (:Person {name: 'Louise Rosol', age: 29}), (:Person {name: 'Bryce Fett', age: 30})"
```

Now you should have 6 nodes of type `Person` in the graph. Let's check them out!

## Basic querying
```cypher
GRAPH.QUERY Social "MATCH (p:Person) RETURN p"
```
Let's analyze this query: `MATCH` is the keyword that describes the relationship between queried entities. It's used to 'match' something in the graph, based on some parameters. In this case we are asking for `Person`, and we alias our results with a `p` (the alias name is not important, you can choose any letter or word).
Nodes are always specified in round brackets.
The `RETURN` keyword returns every `p` found.
So this query returns every `Person` it finds in the graph `Social`.

The resulting graph should be something like this:

![MATCH-ing all nodes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dgbsxxt0l0hystr093uo.png)

The previous query could also be written as:
```cypher
GRAPH.QUERY Social "MATCH (a) RETURN a"
```
This is the generic way to view all nodes in the graph, you'll see this a **lot of times**. Here we are using an alias `a` without asking for a specific node type.

Ok, so let's say we want to retrieve all Person(s) who are exactly 30 years old:
```cypher
GRAPH.QUERY Social "MATCH (p:Person {age: 30}) RETURN p"
```
this query introduces another feature: match for node's attribute. Here we are matching only nodes of type `Person` and with an attribute `age` equal to `30`.
You can query for multiple attributes, by separating `attribute: value` couples with comma between the curly brackets.

Sometimes visualizing a graph of this kind isn't much helpful, a textual result might be more useful.
So click on the `</>` icon just above the last graph and choose `Text`; the output of the last query will be shown as text:

![MATCH results as text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5h3h3bshnyldq5bviy5n.png)

## Connecting nodes and creating edges
Now we add one relation between two nodes:
```cypher
GRAPH.QUERY Social "MATCH (a:Person {name: 'Diana Hendrickson'}), (b:Person {name: 'Susan Hendrickson'}) CREATE (a)-[:KNOWS {relation: 'sister'}]->(b)"
```
The first part of the query is a MATCH to find 2 `Person` ('Diana Hendrickson' and 'Susan Hendrickson'); we alias them with `a` and `b`.  
Then we create the relation:
```cypher
CREATE (a)-[:KNOWS {relation: 'sister'}]->(b)
```
relationships are always written in square brackets. We are binding node `a` and node `b` with a relation of type `KNOWS`. The `KNOWS` relation has an attribute `relation` with value `sister`.

![Edge creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/97vka7xht7waqd60c8cc.png)

Redis is informing us that it has created one relationship with one properties.

> **NOTE:** The correct way to add a relation between existent nodes is by matching them first; if we try to directly create the relationship, like so:
`CREATE (a:Person {name: 'Diana Hendrickson'})-[:KNOWS {relation: 'sister'}]->(b:Person {name: 'Susan Hendrickson'})`
RedisGraph would create 2 new nodes and add the relation between them

The generic query for relationship has this form:
```cypher
(NodeA)-[:Relationship]->(NodeB)
```
take one minute to appreciate how eloquent and visually clear the syntax of Cypher can be😯👏.

Ok, now we can add some more relationships in the graph:
```cypher
GRAPH.QUERY Social "MATCH (a:Person {name: 'Susan Hendrickson'}), (b:Person {name: 'Peter Steinmetz'}) CREATE (a)-[:KNOWS {relation: 'married'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Susan Hendrickson'}), (b:Person {name: 'Louise Rosol'}) CREATE (a)-[:KNOWS {relation: 'friend'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Peter Steinmetz'}), (b:Person {name: 'Bryce Fett'}) CREATE (a)-[:KNOWS {relation: 'friend'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Laura Phillips'}), (b:Person {name: 'Louise Rosol'}) CREATE (a)-[:KNOWS {relation: 'coworker'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Laura Phillips'}), (b:Person {name: 'Diana Hendrickson'}) CREATE (a)-[:KNOWS {relation: 'coworker'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Louise Rosol'}), (b:Person {name: 'Diana Hendrickson'}) CREATE (a)-[:KNOWS {relation: 'coworker'}]->(b)"
```

Let's see what we just did:
```cypher
GRAPH.QUERY Social "MATCH (p:Person) RETURN p"
```
the graph is **exactly** the same as before... why?🤔

The reason is that RedisInshight hides relationships by default; if you enable the "All relationship" slide in the upper right side of the graph, RedisInsight will also show you all the relationships between nodes:

![All edges created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y71johjkstfomdi5jcds.png)

Now try to create a connection between an existent node and a non-existent node:
```cypher
GRAPH.QUERY Social "MATCH (p:Person {name: 'Laura Phillips'}) CREATE (p)-[:KNOWS {relation: 'married'}]->(:Person {name: 'William Stultz', age:33})"
```
RedisGraph creates for us the unknown node (`Person` 'William Stultz') and add the relationship between the known node and the new one.

## Querying for relationships
Now that we've created some "connections" between nodes, we can query the graph for relation between nodes.
Let's say we want to show every married `Person`:
```cypher
GRAPH.QUERY Social "MATCH (p:Person)-[:KNOWS {relation:'married'}]->(o:Person) RETURN p,o"
```

Or we need the list of every `Person` that knows 'Susan Hendrickson':
```cypher
GRAPH.QUERY Social "MATCH (p:Person)-[:KNOWS]-(:Person {name: 'Susan Hendrickson'}) RETURN p"
```
here we made some subtle but important changes to the query: first of all, we don't need the `Person` 'Susan Hendrickson' so we haven't added an alias to it.
Second: in RedisGraph every relation has a direction (starting from Node A ending on Node B). There's no point in giving the `:KNOWS` relation a direction in the last query (two friends are friends to each other, it's a bi-directional relationship).
So we query for the relation without specifying the direction; the syntax `(a)-[:KNOWS]->(b)` became `(a)-[:KNOWS]-(b)`.

What if instead of the list of acquaintances of 'Susan Hendrickson' we want just the count?
We can use the `COUNT` aggregation:
```cypher
GRAPH.QUERY Social "MATCH (p:Person)-[:KNOWS]-(:Person {name: 'Susan Hendrickson'}) RETURN count(p)"
```There is no graph to see here, so RedisGraph only shows the textual output of the `COUNT`:

![COUNT nodes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/maq1hqg8up4p3i3ey805.png)

## Delete nodes and edges
The last query we'll look at today is the `DELETE`:
```cypher
GRAPH.QUERY Social "MATCH (p:Person {name: 'William Stultz'}) DELETE p"
```
again, we first `MATCH` the node, then we `DELETE` it.  
As you may remember, we created a relationship between this node and another `Person` ('Laura Phillips'). When we delete a node, all its relationships are deleted too. This may seems obvious, but it's something to keep in mind.

## RECAP
In this post we learned the basics of Cypher and how to query RedisGraph. The topic is vast, we haveve covered a small part of it just to get you started.

In the next (and last) post, I'll show you a more practical example of RedisGraph in action.