Part X: Aggregations, views and custom relationships

The data API select query is designed to be simple yet powerful. But there are some queries that you cannot express with the select query syntax. For example, getting the number of likes for each article. Aggregations (like count, avg, group_by, etc) are not supported in the select query syntax. This is a conscious decision we have made to keep the query language small.

To express complex queries like aggregations, window functions, custom joins etc, use SQL, which is designed for this purpose. If you can express your query in SQL, you can define a view with it on which you can then use the data APIs as we do on tables.

For example, let’s see how we can get the average rating of all articles written by an author.

Let’s define the view in SQL:

CREATE VIEW author_average_rating AS
    SELECT author.id, avg(article.rating)
    From author, article
    WHERE author.id = article.author_id
    GROUP BY author.id

Now, let’s set this view up on Hasura via the API console:

Navigate to the Data > SQL tab in the API console and enter the above SQL statement. Ensure the This is a migration and Track table boxes are checked so that the query is added as a database migration and the Data microservice is aware of the created view.

../../../_images/tutorial-create-view1.png

Hit Run to create the view on the Postgres database and to track it in the Data microservice (i.e. allow querying via data APIs).

Now, you can use a select query to fetch the author’s average rating as if author_average_rating was a table.

Views are read only!

Views are like read-only logical tables on the database. So that means that data API requests to select will work, but you cannot insert/update/delete items from the view.

Relationships to/from views

We have seen how we can get the author’s average rating using the data APIs. However, additional information of each author can be attached to the author_average_rating view using an object relationship say, author.

All the relationships that we’ve defined till now use foreign key constraints. However, you cannot define foreign key constraints on/to views. So, in these cases, we have to manually define a relationship.

Here, we are defining a relationship from a author_average_rating view to the author table:

../../../_images/tutorial-add-manual-relationship1.png

The above relationship will allow you to fetch the author’s details when querying the view. But we might want to fetch the author’s average rating when querying the author table itself. So we will now create a relationship from the author table to the author_average_rating view:

../../../_images/tutorial-add-manual-rel-from-table1.png

Now, let’s fetch the author details including their average rating:

query fetch_author {
  author(order_by: ["+name"]) {
    id
    name
    average_rating {
      avg
    }
  }
}
POST /v1/query HTTP/1.1
Content-Type: application/json
Authorization: Bearer <auth-token>
X-Hasura-Role: admin

{
    "type" : "select",
    "args" : {
        "table" : "author",
        "columns": [
            "id", "name",
            {
                "name" : "average_rating",
                "columns" : ["avg"]
            }
        ],
        "order_by" : "+name"
    }
}

Note

The above query will work only after adding permissions to the author_average_rating view.

Next: Custom code and microservices

Next, head to Part XI: Custom code and microservices.