Migration to `@forestadmin/agent` - one-to-many relationship with a computed field

We’re migrating from forest-express-sequelize to @forestadmin/agent.

We don’t understand in the docs how to set up a one-to-many relationship with a computed field involved, by defining the in operator in this case.

So we need help with a smart relationship that depends on a smart (computed) field.

The relationship a 1-to-Many: each ExperienceDeparture can have many ActiveReservations, but each Reservation (active or not) belongs to a single ExperienceDeparture.

Previously we had defined the smart relationship as follows:
image (34)


In the new agent we need to define a smart field in the Reservation collection, implement the 'In' operator for that field and reference it in the ExperienceDeparture collection.

This is what we’ve done following this doc:


image (38)

The idExperienceDepartureIfActiveReservation field is correctly calculated and displayed, but I haven’t found a way to make the ‘In’ operator work correctly and hence display the records correctly in the smart relationship.

image (39)

As a workaround we are currently using the emulateFieldOperator.
image (40)

But we’re quite sure there’s a better way to do this and we’re missing something.

May you please help?

Here is the “meta” section of the forest admin schema file:

  {
    "liana": "forest-nodejs-agent",
    "liana_version": "1.41.7",
    "liana_features": null,
    "stack": {"engine": "nodejs", "engine_version": "20.11.1"}
  }

and from package.json:

"sequelize": "^6.28.0"

cc @julien.jolles

Thank you
Matteo

Hello @Matteo ,

Your approach seems right.
I tried to reproduce your issue with your code and the same DB structure, and I encountered the following error when trying to display the experienceDeparture collection: “ValidationError: The given value has a wrong type for "departure_id": 1”

Simply ensuring that values are numbers have solved the issue:
image

Could you let me know if it didn’t solve your issue ?

Hey :wave:

From my understanding of the use-case, the In operator would be a bit more complex to implement.

emulateFieldOperator wasn’t really meant to be use in production case (Or just on really small tables), but mostly a tool build with developer experience in mind (Just to give you something quick to test a computed foreignkey use-case)

In your case, my understanding would be that the actual logic of the smart field will have to be duplicated in the conditionTree.

Something like:

contents.replaceFieldOperator(
  "idExperienceDepartureIfActiveReservation",
  "In",
  async (value, context) => {
    const reservations = await context.datasource
      .getCollection("Reservation")
      .list(
        {
          conditionTree: {
            aggragator: "And",
            conditions: [
              { field: "Booking:Cancellation:id", operator: "Blank" },
              { field: "idExperienceDeparture", operator: "In", value },
            ],
          },
        },
        ["id"]
      );
    return { id: "id", operator: "In", value: reservations.map((r) => r.id) };
  }
);

(Obviously I couldn’t test it with this actual code, but it should give you a good idea of what I mean)

Just as a side note, we have an experimental plugin that should allow you to do that in an easier way.

1 Like

Ok thank you @jeffladiray that’s fine on our side.
We’ll do as you suggest.

At the moment, we’re not confident with the experimental plugin, as in the future you may change something in it, breaking our dependency tree. More over, we just have one case to set up with this technique, so any additional effort to find out a better solution is not worth… We’re just happy to be sure we’re using the new agent correctly.

So ok to adopt your solution :+1:

Maybe, if you’re experimenting this plugin, it will become mainstream in the future, so we may adopt a different approach in the future.

In the mean time, we do agree on you proposed solution.

Thank you very much,
Matteo