Backend Query
Backend Query helps you to trigger a query automatically whenever a user navigates to the page containing the query. You can set a Backend Query on a particular widget or an entire page. The information retrieved using the Backend Query can be used in any widget present inside.
Types of Query
We offer you the following types of Backend Queries that you can specify on any widget or page.
- Query Collection or Table: This query type is used to fetch a single record or a list of records from a Firestore Collection or Supabase Table.
- Document from Reference: Used to retrieve the details from a document reference.
- API Call Query: Used to initiate an API call.
- SQLite Query: Used to execute the SQL statements.
- Algolia Search: Used to trigger an Algolia search on a Firestore Collection.
Difference between Actions & Backend Query
Aspect | Actions | Backend Queries |
---|---|---|
Trigger | Triggered by user interactions such as taps, double taps, or long presses on widgets, or they can be executed automatically on page load. | Automatically triggered when the user navigates to a page or widget containing the query. |
Usage | Can be used to navigate between pages, show messages, update variables, make API calls, and more. | For apps needing instant updates like chat or live scores, Backend Queries can auto-refresh the UI with the latest database changes. |
Multiplicity | You can specify multiple actions on the same widget. | Only one Backend Query can be specified on a particular widget or page. |
Conditional Execution | Can be conditional, meaning they can execute different actions on certain conditions. | - |
Caching | - | Can include caching mechanisms to improve app performance by reducing the number of server calls and providing offline access to data. |
Handling States | - | Often involve handling loading states and empty states, as the data fetching process can take time and might not always return results. |
Data Fetching | - | Only used to fetch data from a backend. |
Change loading indicator
While the backend query is busy retrieving results, it shows the default Project Theme Loading Indicator (which you can change from Navigation menu > Theme Settings > Design System > Loading Indicator.) However, if you want to replace this with a custom loading indicator in a specific backend query, follow the instructions below:
To change the loading indicator:
- Ensure you have added a backend query.
- Open the Backend Query section (on the right side) and scroll down to the Backend Query Loading Widget. Open it by clicking on the arrow icon.
- Set the Loading Widget Type to Image. You can also choose a Component if you have already designed a loading component.
- Enable the View in UI Builder. This allows you to see your custom loading indicator on canvas (before you actually run the app).
- Choose the Image Type, add the image, and adjust its Padding and Width.
- To show the indicator in the center, turn on the Center Image toggle.
- Run the app, and your custom loading indicator will appear while the data is being loaded.
Copy Query
Sometimes, you might want to display the same list of items with a little modification. For example, showing all Todo items and completed Todo items. In such a case, you can copy-paste the entire backend query to speed up the building process. This is helpful, especially when you have a complex backend query.
To copy-paste the query:
- Select the widget (e.g., ListView, GridView, etc.) where you have already added the backend query.
- Select the Backend Query tab, and click the Copy button.
- Now, select the widget (where you want to add the query), move to the Backend Query tab, and click Paste Backend Query button.
- Click Confirm.
Move query to parent widget
You might want to utilize the same backend query on multiple widgets on a page. But if you do so, you end up making redundant server calls for the same thing. So, instead of copying it on every widget, you can move the query to any parent widget. The existing widgets will then use a generated variable derived from the parent widget's query.
To move the query up to any parent widget, simply select the up arrow button and select the parent widget you would like the query to move to.
Displaying empty list widget
The Empty List widget is a widget used to display a message when there are no items in a list. This widget helps to provide a better user experience by displaying a message instead of just an empty screen.
To display the empty list widget:
- Ensure you have added a backend query on any scrollable widget, such as ListView, GridView, Column, Row, DataTable, and StaggeredView.
- Select the scrollable widget (on which you have added the backend query), move to the properties panel, and turn on the Show Empty List Widget.
- Set Widget Type to Image or Component. The further options are available based on what you choose.
- Try toggling the View in UI Builder. This allows you to see your empty list widget on canvas (before you actually run the app).
- You can also control the size and centering of the widget using the available options.
Backend Query Caching
Backend query caching refers to the process of storing the result of a backend query in a cache so that subsequent queries for the same data can be served directly from the cache rather than making a new query to the backend.
Caching a query can bring significant benefits to your app, including improved performance and reduced server load. Additionally, caching can enable your app to function offline by serving cached results when there is no internet connection available.
For example, an e-commerce app can cache product data, such as product descriptions, prices, and images, to avoid making unnecessary API calls for each page load.
Caching backend queries works for all types of queries.
For Firebase queries, enable Single Time Query if you want the query to fetch data only once. Otherwise, the query operates in real-time, updating automatically as soon as the data changes.
When to cache
In general, any data that is static, slowly changing, or read more often than they are updated can be cached to improve performance and reduce the load on the server. A few examples are
- Static content such as images and videos.
- Configuration data such as application settings or system parameters.
- Data that is expensive to compute, such as complex reports or analytics.
When NOT to cache
Sometimes, it's not a good idea to cache the backend query. Here are some examples:
- Large amounts of data can cause performance issues and may not be appropriate.
- Sensitive or confidential data should not be cached, as it could lead to unauthorized access.
- Frequently changing data, such as in real-time or near real-time scenarios, caching may not be appropriate as the cached data could quickly become stale or outdated.
- Critical response time where the data needs to be up-to-date and accurate at all times.
Example
Let's see how to cache a backend query with an example app that shows a list of employees on the first page and employees' details on the second page. On the employee details page, the data is retrieved from a backend query and read more often than they are updated, so it's a good candidate to cache.
To improve performance, you can cache the data on the details page so that it can be quickly retrieved and displayed to users.
Here is how it looks:
In the visual above, see how the loading indicator appears for the first time a query is made on the page. However, subsequent queries will retrieve the result from the cache, and the loading indicator will not be displayed again.
To cache the backend query:
- Ensure you have added a backend query. For this example, to retrieve data from a Firebase document, we add a backend query at the page level as Single Time Query. We use a document reference to get the employee details.
- Open Query Cache Settings and Enable Query Caching.
- Determine the Scope of the cache. If you set it to App Level and the exact same query is made on any other page of the app, it will display the result from the cache. However, if you set the Page Level, the cached result will be used only on that page if the query is made multiple times on the same page.
- If the current query is completely new/different, create a Query Name. If not, and you want to use the cached result of this query (that might be created somewhere else), select the name from the list.
- If we leave this example here, we'll have data inaccuracy issues. That means when any employee data is cached, the same data will be used for all employees, which is not what we want. We want to cache data for all individual employees. To do so, we can set the Unique Key. Here the unique key can be the employee id or the document reference.
- Data inaccuracy without Unique Key
- Adding Unique Key
-
At this point, we have enabled the caching, but we still have one problem. Once the query is cached, it will be used forever, although we update the data in our backend. This is because we are not clearing or invalidating the cache at the appropriate time. To properly invalidate the cache, you can use the Should Override Cache property OR Clear Query Cache action. This helps you remove the cached data that has become stale or outdated.
- The Should Override Cache property accepts a boolean (True/False). That means we can provide a variable (e.g., an App State variable named isCacheOverride) that knows when to override the cache. So create one and set it here.
- Create one more App State variable, something like lastCacheTime, and set the current time as default. This will be used to save the time of results retrieved from the backend. You'll better understand how helpful it is in the logic we add in the next step.
-
Now, we must add a logic that determines whether to override the cache (every time when the page is loaded) and set the isCacheOverride variable accordingly. Here is how it goes:
- First, check if the lastCacheTime is set or not. If not, set the current time to it.
- Then the idea is to create one custom action that checks if the current time is more than 30 minutes ahead of the lastCacheTime. Note that 30 minutes is the cache expiration time, and here, it is kept minimum just for simplification purposes; It's important to carefully choose the appropriate expiration time for your cache based on the nature of your data.
- if True :
- Update the lastCacheTime with the current time and isCacheOverride to True. Make sure you keep the Update Type to Rebuild Current Page so that the backend query is made again, which will invalidate the cache and display updated data.
- You can also add an action to Clear Query Cache.
- Continuing the same action flow, wait for 1 sec and again update isCacheOverride to False so that the cached result won't override on page load for the next 30 min.
Note that in this example, we use both the Clear Query Cache action and the Should Override Cache property to clear or invalidate the cache. Although both perform the same task, it's generally considered better practice to explicitly Clear Query Cache rather than relying on the Should Override Cache bool. However, in certain cases, you may want to override the cache conditionally instead of with an explicit action, so the option is there.
Here is how the custom function looks in case you want to check:
bool isOverrideCacheAction(DateTime cacheTime) {
// Add your function code here!
return DateTime.now().difference(cacheTime).inMinutes > 30;
}
You can have a separate lastCacheTime variable for all the employee records to avoid any conflict with others. Failing to do so may keep on updating the common lastCacheTime variable, and you might not see updated data. For example, creating a list of JSON that contains the id and lastCacheTime of an employee might help. Like this:
{ "id": 1, "lastCacheTime": '2023-03-22T14:30:00+00:00', }
Clear Query Cache [Action]
This action provides a simple way to clear the query cache, which can be helpful in situations where the cached data is no longer accurate or needs to be refreshed. By executing this action, you reset the query cache, allowing the app to fetch and display the most up-to-date data.
This can help improve app performance and ensure users see the most recent information available.
Follow the steps below to add this action to any widget.
- Select the Widget (e.g., Container, Button, etc.) on which you want to add the action.
- Select Actions from the properties panel (the right menu), If it's the first action, click + Add Action button. Otherwise, click the "+" button below the previous action tile (inside Action Flow Editor) and select Add Action.
- Search and select the Clear Query Cache (under State Management) action.
- Determine the Scope of the cache, whether it lives at the App Level or Page Level.
- Set the Query Name to the one you gave while adding the query cache.
- If you have set the Unique Key while caching a query, you should add the same key here as well. This ensures that the cache will be removed only for specific data.