It's better to understand GraphQL as a protocol that competes with REST. It's only a language in the sense that JSON is a language; i.e., it has a syntax that can be parsed.
For example, GraphQL supports queries like this:
query movie {
whereYear(max: 1985)
actors {
hasName(like: "goldblum")
}
}
But this is something the particular schema and implementation would need to implement. If you want to filter by arbitrary attributes, you're out of luck because the spec is just a syntax. I suppose you do something like: where(what: "year", max: 1985)
but you still have to invent a standard set of parameters here: min, max, eq, notEq, lessThan, lessThanOrEq, like, etc. Again, totally ad hoc.GraphQL, not being a language, also doesn't support variable bindings. So you cannot do self-referencing queries like "find all movies with a director who also acted in it", because that would require some kind of variable support.
(This is not a criticism of GraphQL, by the way. It's great at what it's defined for.)
So, for people more comfortable with SQL, your question could just as well be "what can SQL do that GraphQL can't"?
The answer is, of course, that they occupy different domains and have different functions. Both can do lots of things that the other can't.
Here are some use cases I think Cypher expresses nicely that I (as a GraphQL noob) don't know how to do in GraphQL:
Simple recommendation engine - suggest people with lots of friends in common that I don't already know;
MATCH (me:User)-[:KNOWS]->(friend)-[:KNOWS]->(fof)
WHERE NOT (me)-[:KNOWS]->(fof)
AND id(me) = blah
RETURN fof.name, count(friend) AS friendsInCommon
ORDER BY friendsInCommon DESC
Basic routing - what's the shortest way for me to get to work? MATCH p = shortestPath( (home:Address)-[:ROAD*]-(work) )
WHERE home.street = .. AND work.street = ..
RETURN p g.V(blah).out("knows").aggregate("friends").
out("knows").where(not(within("friends"))).
select().
by("name").
by(count("friends")).
order().by(valueDecr) MATCH (me:User)-[:KNOWS]->(friend)-[:KNOWS]->(fof)
WHERE NOT (me)-[:KNOWS]->(fof)
This easily reads as "get friends (AS FOF) [who know] friends [who know] me, where me [does not know] FOF" to me. out("knows").aggregate("friends").
out("knows").where(not(within("friends")))
The Gremlin, on the other hand, reads as "get friends [who know] friends where... friend is not a friend???" to me.I also don't easily see where something should be a method and where it should be a function. Why not `order(by(valueDecr))`? Why not `select("name", count("friends"))`? Why not `where(not().within("friends"))`?
SELECT ?foaf
WHERE
{
?me a <USER> .
?me <KNOWS> ?friend . ?friend <KNOWS> ?foaf .
MINUS {:me <KNOWS> ?foaf }
}
OR SELECT ?foaf
WHERE
{
?me a <USER> .
?me <KNOWS>/<KNOWS> ?foaf .
MINUS {:me <KNOWS> ?foaf }
} out("knows").aggregate("friends").out("knows").where(not(within("friends")))
OR out("knows").aggregate("friends").
out("knows").where(not(within("friends")))
Note the "." concatenation that ties the two lines together into a chain. When nesting parallel traversals (e.g. match()), the traversal patterns are delineated by ",". . = AND
, = OR
Ha. Thats a generally neat way to think of "." and "," in computing. mult and + ...the algebra.I find what they have defined so far far more approachable than Cypher or Gremlin. As they have been adding features it is starting to sprawl and look just as nutty as the others. But I do like how it is defining the whole ecosystem around how graphs can be defined and interacted with, much like Gremlin has, but with a much more focused and disciplined approach.