Update: Dgraph have renamed its query language. It used to be called GraphQL±, and now it is DQL.
Abstract
In my humble opinion. Cypher is not Graphs friendly. But it’s not that hard to understand. It tries to maintain concepts of SQL RDBMS. For me, it’s a waste of time. We should invest in a language similar to Graph’s own structure, to dive into the paradigm. Just like GraphQL does. And that’s where DQL
is inspired from.
Another detail I see is that Neo4J is CSV dependent. Maybe it has some advantage for them to use CSV. But in part, this adds an extra layer of complexity for users to create relationships. For CSV, in general, has no relations. They are just tables. After you add datasets in CSV you need to create relations. You need to know Cypher well and your own dataset to create accurate relationships.
I am not an expert on Cypher. But that’s what it seems to me.
Unraveling Cypher Query
MATCH (m:Person {name: 'Mark'})
RETURN m
So, everything inside the parentheses is a “node” (e.g. CREATE (n),(m)
= two nodes). Everything before : (double dots) is a “variable”. And you can directly consider it like our value variable(Get started with Dgraph).
After the double dots is the “type” of the Node itself, in Neo4j context is called “Label”. So you can directly consider it like our type system see Get started with Dgraph. So CREATE (n:Person:Swedish)
would be a node with multiple types.
Inside the Curly brackets(braces{}) is the body of the query merged with the function. So to translate this you need to set the func to “eq(name, “Mark”)” and inside the DQL
body use { name }
.
In DQL
{
user(func: type(Person)) @filter(eq(name, "Mark")) {
name
}
}
Continuing
MATCH (a:Person),(b:Person)
WHERE a.name = 'A' AND b.name = 'B'
CREATE (a)-[r:RELTYPE]->(b)
RETURN type(r)
So in this Cypher query we have 2 nodes to find. And it gonna create a relation between them. As you can see it is ( Node from var a )-[ Var : EDGE ]->( Node from var b)
. So everything in brackets will be an edge that follows a direction if you set ->
. See our concet of Edges Get started with Dgraph
BTW, Every time you see the pattern “MATCH + CREATE or MERGE” in any Cypher context. This means she is analogous to Upsert Block.
In DQL
upsert {
query {
A as var(func: type(Person)) @filter(eq(name, "A"))
B as var(func: type(Person)) @filter(eq(name, "B"))
}
mutation {
set {
uid(A) <RELTYPE> uid(B) .
}
}
}
Node or Relationship Properties / Facets
MATCH (p:Person {name: 'Jennifer'})-[rel:IS_FRIENDS_WITH {since: 2018}]-> (X)
RETURN X
MATCH (n)-[:REL {status:"good"}]->()
Relationship property in Neo4J is analogous to the Facet we have in Dgraph. Both have the same purpose, but apparently work internally differently in Neo4J. By the way, Facets in Dgraph are bidirectional. So when you use Reverse Edges in Dgraph. There will be the same facets for both directions.
Well, to identify when Cypher uses properties in relationships. Just see that inside the edges there is a Curly brackets. In the first example, {since: 2018}
is the “Facet” of this Cypher query. And {status:"good"}
is the “Facet” of the second.
See more about Facets here.
Get directions
example 1
//data stored with this direction
CREATE (p:Person)-[:LIKES]->(t:Technology)
In RDF (Single direction p -> t
)
{
set {
_:p <LIKES> _:t .
_:p <dgraph.type> "Person" .
_:t <dgraph.type> "Technology" .
}
}
Use Reverse to know “Who likes Technology”.
Ref: Get started with Dgraph
In DQL
{
q(func: type(Technology)) {
fans_Of_tech : ~LIKES {
name #?
age #?
dgraph.type #it gonna be "Person".
}
}
}
example 2
//query relationship backwards will not return results
MATCH (p:Person)<-[:LIKES]-(t:Technology)
In Dgraph’s lang, we don’t have this concept of reverse direction to be the pivot of the relationship. We have only one direction which is p -> t
. If you wanna see it as “reverse” you have to specify in the schema as @reverse
. So you get what you want a sort of “p <- t
”.
So if you still wanna do this, the direction p <- t
in Dgraph is a bit odd (I think), cuz It is like “Technology likes Person”.
So reverse is better in case you just wanna “get known about the parent of that node” or a list of “users” who “like/knows/bought/checked/visited/view” that entity.
In any case In RDF (Single direction p <- t
which is actually t -> p
)
{
set {
_:p <dgraph.type> "Person" .
_:t <LIKES> _:p .
_:t <dgraph.type> "Technology" .
}
}
In DQL
{
q(func: type(Technology)) {
LIKES {
dgraph.type
}
}
}
example 3
//better to query with undirected relationship unless sure of direction
MATCH (p:Person)-[:LIKES]-(t:Technology)
In RDF (double direction p <-> t
)
{
set {
_:p <LIKES> _:t .
_:p <dgraph.type> "Person" .
_:t <LIKES> _:p .
_:t <dgraph.type> "Technology" .
}
}
In DQL
{
q(func: type(Person)) {
LIKES {
dgraph.type
~LIKES {
dgraph.type #This will return the reverse of the Technology entity, which is the Person itself.
}
}
}
}
Or
{
person(func: type(Person)) {
dgraph.type
LIKES {
dgraph.type
}
}
Tech(func: type(Technology)) {
dgraph.type
LIKES {
dgraph.type
}
}
}
The Basics operations / Cypher Keywords
MATCH
It is the mix of query body and root function.
CREATE
Simple operation to create nodes.
MERGE
Is a kind of Upsert Query (And Bulk upsert). In Cypher terms it is like a combination of MATCH and CREATE.
RETURN
This concept doesn’t exist in DQL
. But could be implemented in Upsert blocks.
DELETE
The delete operation depends on the Neo4J’s “Value Variable”. The whole Cypher is a kind of “Upsert Block like” query. It deletes the Node set in the “Value Variable”.
DETACH
This operation just remove edges between nodes.
DETACH DELETE
This does the same as the last one but deletes the node, set in the “Value Variable”. Also this “detach” incoming edges. In Dgraph’s terms It means, it removes the “reverse” edges at the same time it deletes the node.
REMOVE
This operation just remove values/predicates from the node.
SET
This operation adds or updates values/predicates in the node.
WHERE
It’s an extension of a set of params for the “root query”. Neo4J’s Cypher separate "where, Match and so on to keep the same logic line of operations in RDBMS.
Continuing
In this post, I will get some queries from Cypher and “translate” to DQL
. It may help some people who are already familiar with Cypher to become familiar with DQL
.
Well, If you have any query you wanna me to “translate”, please feel free to ask bellow.
ref: Neo4j Query Language - Cypher
In Neo4j
MATCH (p:Person { Name:"Homer Flinstone" })
RETURN p
In DQL
{
q(func: type(Person)) @filter(eq(Name, "Homer Flinstone")){
Name
}
}
Ref: Neo4j - Create a Node using Cypher
CREATE (a:Artist { Name : "Strapping Young Lad" })
In RDF (you can also use JSON)
{
set {
_:Node <Name> "Strapping Young Lad" .
_:Node <dgraph.type> "Artist" .
}
}
And
CREATE (b:Album { Name : "Heavy as a Really Heavy Thing", Released : "1995" })
RETURN b
In RDF
{
set {
_:Node <Name> "Heavy as a Really Heavy Thing" .
_:Node <Released> "1995" .
_:Node <dgraph.type> "Album" .
}
}
We don’t have a “return”. You need to do a query for it.