As a developer, I really want to be able to get the data back from my API in a single request so that my application performs better and I don’t get socked with excessive API requests that result from “chatty” APIs.
One of the things that developers love about FatFractal is the way that you can construct queries that can get you to what you want in a single round-trip.
First, the basics – FatFractal queries…
- …are written in an easy to create, easy to read, natural language style.
- …can be chained together to filter the results to only the results you want in a single request.
- …are able to “walk” your object graph in both directions.
- …provide the best of relational capabilities without the complexity.
- …are constructed as strings, not proprietary query objects.
- …includes a very useful random operator that for some reason, nobody else seems to offer.
Let’s say that you have movie Star, Movie and Theater objects and their respective collections (Stars, Movies and Theaters) and you want to get all the theaters that are showing movies that have a particular star acting in them within a defined distance from the user. The following explains how you can create a query string that can return that in a single request/ response to illustrate the power of nesting queries in a single construct:
/Stars/(firstName matches ‘(%3Fi)milla’ and lastName matches ‘(%3Fi)jovovich’)/BackReferences.Movies.stars/()/BackReferences.Theaters.movies/(distance (location, [57.5833, 3.8667]) lte 5000)?sort=rating desc, name asc&count=5&first=0
Creating or reading FatFractal queries goes left to right, with query constituents enclosed in parentheses with “traversals” and queries separated by forward slashes. So, breaking down the query above into pieces:
/Stars/(firstName matches ‘(%3Fi)milla’ and lastName matches ‘(%3Fi)jovovich’)The first part (a query) will get the movie star(s) (Star object) from the Stars Collection with the firstName member ‘Milla’ and the lastName member ‘Jovovich’, using regular expressions that compare while ignoring case (requires proper encoding of the Java regex mode modifier ?i for ignore case to be added as %3Fi) and a boolean operator (and) to ensure a complete match. Note: we now have a set of Star objects, probably with a single object.
/BackReferences.Movies.starsThe second part (a traversal) will then get all the Movie objects that she starred in based on the BackReferences from the Movie objects in the Movies Collection to the star in the Stars Collection. Note: we now have a set of Movie objects.
/()The third part (a query) is an empty query operator that says that will use the entire set returned by the traversal.
/BackReferences.Theaters.moviesThe fourth part (a traversal) will then get the Theater objects from the Theaters Collection that are showing movies that Milla Jovovich starred in from the BackReferences from the Theater objects in Theaters Collection to the above set of Movie objects in the Movies Collection. Note: we now have a set of Theater objects, which is what we want.
/(distance (location, [57.5833, 3.8667]) lte 5000)The fifth part (a query) will then filter that set of Theater objects by geolocation that are within 5 kilometers of the user.
?sort=rating desc, name ascThe sixth part (a sort) will then sort them first by the rating member of the Theater objects in descending order, second by name member of the Theater objects in ascending order.
&count=5&first=0Lastly, we then limit the result set of Theater objects to the first 5 items or less.
So, basically we start from a Star object in the Stars Collection, walk the datagraph to Movies using a BackReference, then walk the datagraph again to Theaters using another BackReference, and then filter the set of Theater objects further based on location, order the results by both the rating and name member values and limit the number of responses to a specified maximum count. Voila – you get what you want, ordered as you want, all in one go with a single, easy to understand query – this simply cannot be done with any other BaaS provider.
Also, let me point out the random operator in the FatFractal query language as it is an example of a very common use case.
Let’s say you want to retrieve a random movie Star from the Stars collection. The query looks like this:
“/Stars/(guid eq random(guid))”
This is incredibly useful as otherwise, you would have to retrieve the entire set of Star objects from the Stars collection over the wire and then pick a random one from that set in your client code. Easy enough to program, but grossly inefficient in terms of client resources and network performance. Otherwise, you could *probably* retrieve a random item with two queries – first, by querying the collection to get a count, and if the API has an ordered ID (as many do), then you could generate a random ID in your client code and fetch that one (hoping that it has not been deleted). At any rate, getting a random object from a collection is a very common use case and I do find it bizarre that nobody else support this as easily as FatFractal does and forces you to use very inelegant client solutions.
One more point to make is that queries can be used in the context of GETS as well as within Server Extensions and Event Handlers.
All for now – have fun with your queries!
For more information on FatFractal Query language, the docs are here.
For more information on how to write queries with FatFractal, the docs are here.