Create a Smart relationship
Please be sure of your agent type and version and pick the right documentation accordingly.
This is the documentation of the forest-express-sequelize and forest-express-mongoose Node.js agents that will soon reach end-of-support.
forest-express-sequelize v9 and forest-express-mongoose v9 are replaced by @forestadmin/agent v1.
Please check your agent type and version and read on or switch to the right documentation.
This is still the latest Ruby on Rails documentation of the forest_liana agent, you’re at the right place, please read on.
This is the documentation of the django-forestadmin Django agent that will soon reach end-of-support.
If you’re using a Django agent, notice that django-forestadmin v1 is replaced by forestadmin-agent-django v1.
If you’re using a Flask agent, go to the forestadmin-agent-flask v1 documentation.
Please check your agent type and version and read on or switch to the right documentation.
This is the documentation of the forestadmin/laravel-forestadmin Laravel agent that will soon reach end-of-support.
If you’re using a Laravel agent, notice that forestadmin/laravel-forestadmin v1 is replaced by forestadmin/laravel-forestadmin v3.
If you’re using a Symfony agent, go to the forestadmin/symfony-forestadmin v1 documentation.
Please check your agent type and version and read on or switch to the right documentation.
Create a Smart relationship
What is a Smart Relationship?
Sometimes, you want to create a virtual relationship between two set of data that does not exist in your database. A concrete example could be creating a relationship between two collections available in two different databases. Creating a Smart Relationship allows you to customize with code how your collections are linked together.
Create a BelongsTo Smart Relationship
On the Live Demo example, we have an order which belongsTo a customer which belongsTo a delivery address. We’ve created here a BelongsTo Smart Relationship that acts like a shortcut between the order and the delivery address.
A BelongsTo Smart Relationship is created like a Smart Field with the reference option to indicate on which collection the Smart Relationship points to. You will also need to code the logic of the search query.
const { collection } = require('forest-express-sequelize');
const models = require('../models');
collection('orders', {
fields: [{
field: 'delivery_address',
type: 'String',
reference: 'addresses.id',
get: function (order) {
return models.addresses
.findAll({
include: [{
model: models.customers,
where: { id: order.customer_id },
include: [{
model: models.orders,
where: { ref: order.ref }
}]
}],
})
.then((addresses) => {
if (addresses) { return addresses[0]; }
});
}
}]
});Ensure the file app/forest/__init__.py exists and contains the import of the previous defined class :

Create a HasMany Smart Relationship
On the Live Demo example, we have a product hasMany orders and an order belongsTo customer. We’ve created a Smart Relationship that acts like a shortcut: product hasMany customers.
A HasMany Smart Relationship is created like a Smart Field with the reference option to indicates on which collection the Smart Relationship points to.
Upon browsing, an API call is triggered when accessing the data of the HasMany relationships in order to fetch them asynchronously. In the following example, the API call is a GET on /products/:product_id/relationships/buyers.
Option 1: using Sequelize ORM
We’ll use the findAll and count methods provided by Sequelize to find and count all customers who bought the current product (buyers).
Then, you should handle pagination in order to avoid performance issue. The API call has a query string available which gives you all the necessary parameters you need to enable pagination.
Finally, you don’t have to serialize the data yourself. The Forest Admin agent already knows how to serialize your collection (customers in this example). You can access to the serializer through the recordsGetter.serialize function.
Option2: using raw SQL
We’ll use raw SQL query and Sequelize to count and find all customers who bought the current product (buyers).
Then, you should handle pagination in order to avoid performance issue. The API call has a query string available which gives you all the necessary parameters you need to enable pagination.
Finally, you don’t have to serialize the data yourself. The Forest Admin agent already knows how to serialize your collection (customers in this example). You can access to the serializer through the recordsGetter.serialize function.
If your primary key column name (customer_id) is different than the model field name (customerId), you must alias the primary key column with the name of the model field in the dataQuery.
Ex: SELECT customers.*, customers.customer_id AS “customerId”
Upon browsing, an API call is triggered when accessing the data of the HasMany relationships in order to fetch them asynchronously. In the following example, the API call is a GET on /Product/:product_id/relationships/buyers.
We use the $lookup operator of the aggregate pipeline. Since there's a many-to-many relationship between Product and Customer, the $lookup operator needs to look into orders which is an array we have to flatten first using $unwind.
Finally, you don’t have to serialize the data yourself. The Forest Admin agent already knows how to serialize your collection (Customer in this example). You can access to the serializer through the Liana.ResourceSerializer object.
Upon browsing, an API call is triggered when accessing the data of the HasMany relationships in order to fetch them asynchronously. In the following example, the API call is a GET on /Product/:product_id/buyers.
We’ve built the right SQL query using Active Record to count and find all customers who bought the current product.
Then, you should handle pagination in order to avoid performance issue. The API call has a querystring available which gives you all the necessary parameters you need to enable pagination.
Finally, you don’t have to serialize the data yourself. The Forest Admin agent already knows how to serialize your collection (Customer in this example). You can access to the serializer through the serialize_models() function.
Upon browsing, an API call is triggered when accessing the data of the HasMany relationships in order to fetch them asynchronously. In the following example, the API call is a GET on /app_product/:product_pk/relationships/buyers.
You will have to declare this route in your app urls.py file
Then create the pertained view
We’ve built the right SQL query using Django ORM to find all customers who bought the current product.
Then, you should handle pagination in order to avoid performance issue. The API call has a querystring available which gives you all the necessary parameters you need to enable pagination.
Finally, you don’t have to serialize the data yourself. The Forest Admin agent already knows how to serialize your collection (Customer in this example, with the table name app_customer). You can access to the serializer through the Schema().dump function (using marshmallow-jsonapi internally).
Upon browsing, an API call is triggered when accessing the data of the HasMany relationships in order to fetch them asynchronously. In the following example, the API call is a GET on /product/{id}/relationships/buyers.
We’ve built the right SQL query using Active Record to count and find all customers who bought the current product.
Then, you should handle pagination in order to avoid performance issue. The API call has a querystring available which gives you all the necessary parameters you need to enable pagination.
Finally, you don’t have to serialize the data yourself. The Forest Admin agent already knows how to serialize your collection (Customer in this example). You can access to the serializer through the render() function of JsonApi facade.

Last updated
Was this helpful?