Published in


Announcing New Functions in FQL

We’re pleased to announce new FQL capabilities that provide better support for query patterns common to smaller scale deployments, and favor flexibility and expressivity over raw scalability. With these updates, users are able to write more concise and powerful FQL statements with Range(), Filter(), Reduce(), and Merge() functions.

Please note that these new functions are in Preview mode, which means that they will be continuing to improve over the next month and we invite you to send us feedback about their use.

New functionality has been added via a combination of new FQL functions and enhancements to existing ones. To learn more, please check out our documentation.

Range() function

Range(set, from, to)

Range() provides the ability to limit a set based on lower and upper bounds of its natural order. For example, given the index:

"name": "users_by_name",
"source": Collection("users"),
"terms": [],
"values": [{"field": ["data", "name"]}, {"field": "ref"}]

Range() may be used to get a range of users by name:

Range(Match("users_by_name"), "Brown", "Smith")

If a set’s tuples are longer than the bounds passed to Range(), the limit applies based on the prefix the bound covers. For example, if the above index covered discrete fields for last name and first name, an array argument to Range() will be interpreted as a tuple prefix:

Range(Match("users_by_last_first"), ["Brown", "A"], "Smith")

Range() is inclusive. Other range-like predicates to be added are RangeLT, RangeLTE, RangeGT, and RangeGTE, which let you bound the set only on one side, or which can be combined to specify upper and lower bound exclusivity.

Filter() function

Filter(set/array/page, predicate)

Before this release, Filter() took an array or page and filtered its elements based on a predicate function. It has been enhanced to work on sets, in order to enable more ergonomic pagination and the ability to compose it with other set modifiers.

For example, let’s use Filter() on our index above to find all names over a certain length:

Filter(Match("users_by_name"), (name, r) => GT(Length(name), 20))

Reduce() function

Reduce(set/array/page, init, fn)

We’ve added a Reduce() function to FQL. You may be familiar with “fold” or “reduce” from functional languages, which let you reduce a container such as an array, down to a summary value. FQL’s new Reduce() function brings this capability to sets, arrays, and pages in your FaunaDB queries.

Here’s how to count the number of users with an “all_users” index:

Reduce(Match("all_users"), 0, (x, count) => Add(1, count))

Format() function

Format(template, v1, …, vn)

The new Format() function takes a string template and one or more values which are inserted into the template based on c-style formatting rules:

Format("Alex is %d years old.", 12)

See the documentation on Format() for more details, including template options.

Merge() function

Merge(obj1, obj2, lambda)

Merge() combines two objects, and takes an optional lambda which lets you resolve conflicts between the two objects.

By default, if there is a conflict, the value from the second object is used:

Merge({ "a": 1, "b": 1 }, { "b": 2, "c": 2 })

{ "a": 1, "b": 2, "c": 2 }

The optional lambda is used to control how conflicts are resolved:

Merge({ "a": 1, "b": 1 }, { "b": 2, "c": 2 }, (k, l, r) => Add(l, r))

{ "a": 1, "b": 3, "c": 2 }

Translating OpenCRUD predicates

Listening to our users

The request for many of these new functions came from our friends at GraphCMS, who helped identify additional areas for growth in our FQL API. Creating these new functions has enabled us translate OpenCRUD predicates into queries on a single field sorted index, which was another request from GraphCMS that we were excited to fulfill.

Given the below index, which has no partition terms, and covers a field and the document ref:

"name": "coll_by_x",
"source": Collection("a_collection"),
"terms": [],
"values": [{"field": ["data", "x"]}, {"field": "ref"}]

Below are FQL representations of OpenCRUD single field equality predicates:

field (equals):

Range(Match("coll_by_x"), <value>)

field_not (not equals):

Filter(Match("coll_by_x"), (x, r) => Not(Equals(x, <value>)))

field_in (in list):

Union(Map(<values>, n => Range(Match("coll_by_x"), n))

field_not_in (not in list):

Filter(Match("coll_by_x"), (x, r) => And(Map(<values>, v => Not(Equals(v, x)))))


Range(), Filter(), Reduce(), Format(), and Merge() allow you to write more expressive FQL, and push more computational logic down to the database. Please visit our documentation to learn more. And please let us know what you think so that we can incorporate your feedback into the formal release.

What other functions would you like to see implemented in FaunaDB? Please reach out to me on our Community Slack and describe any other features that would make FaunaDB an obvious choice for your next project.

Author: Lewis King
Date: September 3, 2019
Originally published at




Fauna is a distributed document-relational database delivered as a cloud API. Build new or migrate existing applications to Fauna and scale without worrying about operations.

Recommended from Medium

Flutter responsive design : size doesn’t (always) matter

You want to teach what you learn! GitHub awards & communities — Code Inspector Talks

Reversing a String in Python

18 Of The Best Elixir Resources Available Online in 2020

Architecting the Ethereal Language

The differences between a static library and a dynamic library

Best Azure Optimization Tools for 2022

How To Become a Game Developer and Make Money

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Fauna Inc

Fauna Inc

Fauna is a distributed document-relational database delivered as a cloud API.

More from Medium

Understanding Typescript Distributive Conditional Types with a Source Code Debugging Approach

Generics in typescript

Adding TypeSafety to Electron IPC with TypeScript

Using TypeScript in NiFi ExecuteScript