Related data not displaying correctly with smart field as reference field

Hi, it is me again :wave:,

The reference field of a related data is not loading properly when the related model has not been “opened”/loaded.

I have a model with multiple related data model:
image

When I click on Materials, I want to see this screen:


Behind black square is the name of the Material Per Origin, which is a smart field used as the reference field of the model.

But sadly the data is not displayed correctly when I just load a fresh page:

To fix this thing I have to load the model and after that the correct reference field is used.

Is there something I can do to not manually load the related model in order to see the correct reference field ?

Context

Materials is actually a table named Material Per Origin that have 2 joints: one on Materials and one on Origins.

Forest Express: 8.5.1
Express Version: 4.17
Sequelize Version: 7.9.1
Database Dialect: PostgreSQL
Database Version: 13

Hey @LotusBlack,

Sorry for the delayed reponse, I’m trying to reproduce your issue on my end and i’ll ping you when I’ve got news to share.
I may have misunderstood your setup however, do you have a schema for this part of your database setup (That you can share here or in private if you consider it as sensible informations)? I’m actually not sure to understand the whole relation between the smart field/reference and your database structure.

Thanks for your help

Hi @jeffladiray

I can send you a video by pm.
Let me know if it answer to your questions?

Btw, I still have the issue as of today.

Thanks,

1 Like

Do you also have the definition of the smart relationship?

I’m guessing that the response of the route containing the smart relationship does not embed the name by default, maybe related to the version of forest-express-sequelize you are using? Could you also share this information here?

Thanks in advance

Smart relationship definition

  PackagingPerMaterial.associate = (models) => {
    PackagingPerMaterial.belongsTo(models.materialPerOrigin, {
      foreignKey: {
        name: 'idMaterialPerOriginKey',
        field: 'id_material_per_origin',
      },
      as: 'idMaterialPerOrigin',
    });
    PackagingPerMaterial.belongsTo(models.packagings, {
      foreignKey: {
        name: 'idPackKey',
        field: 'id_pack',
      },
      as: 'idPack',
    });
  };

Forest version

    "forest-express": "^8.5.1",
    "forest-express-sequelize": "^7.9.4",

The definition you shared is not a smart relationship, but a “classic” sequelize relation, using a FK.

Behind black square is the name of the Material Per Origin, which is a smart field used as the reference field of the model.

This was the definition I was asking for. Sorry for being unclear here :sweat_smile:.

My guess here is that the definition of this smart field does not embed the name (Thus display the id by default), and once the record is fully loaded, then it’ll display the name (Which is the behavior you are having).

Ok my bad.
Does this answer to your request ?

collection('materialPerOrigin', {
  actions: [],
  fields: [{
    field: 'material_and_origin',
    type: 'String',
    get: (materialPerOrigin) => {
      return materialPerOrigin.idMaterial.name + ' ' + (materialPerOrigin.idOrigin ? materialPerOrigin.idOrigin.name : '');
    },
    search: function (query, search) {
      let split = search.split(' ');
      
      query.include.push({
          model: models.materials,
          as: 'idMaterial'
        });
        query.include.push({
          model: models.origins,
          as: 'idOrigin'
        });
    
      query.where[Op.and][0][Op.or].push(
        models.objectMapping.literal(`"idMaterial"."name" ILIKE '%${split[0]}%'`)
      );
    }
  },],
  segments: [],
});

I am displaying the name right ? In the Get part ?

Thanks for your help @jeffladiray !

1 Like

Let me know if I understood everything correctly:

  • The collection materialPerOrigin has a smart field material_and_origin, and it is used as a display reference field.
  • The collection material has one materialPerOrigin.
  • You want to display material_and_origin as the reference field of materialPerOrigin when displaying material.

If I’m correct, the behavior you are having is indeed a bug that’ll try to reproduce on my end.

Let me know :pray:

1 Like
  • The collection materialPerOrigin has a smart field material_and_origin , and it is used as a display reference field.

That’s right

  • The collection material has one materialPerOrigin .

No, the collection material can have multiple materielPerOrigin. Glass can be recycled or blank.

  Materials.associate = (models) => {
    Materials.hasMany(models.materialPerOrigin, {
      foreignKey: {
        name: 'idMaterialKey',
        field: 'id_material',
      },
      as: 'idMaterialMaterialPerOrigins',
    });
  };
  • You want to display material_and_origin as the reference field of materialPerOrigin when displaying material .

I want to display material_and_origin as the reference field of materielPerOrigin when I am displaying the data for materialPerOrigin.
When I am looking at the table Packaging_per_material I want to see the smart field/reference field material_and_origin and not the id.

I am attaching a screenshot of the schema.

Thanks for the help, I’m able to reproduce the issue on my end as well.

My understanding of the current code for your case is that:

materialPerOrigin retrieve and compute the smart field value on the resolved (materialPerOrigin) => ... - in the case of the materialPerOrigin table, the value includes the related data for both material & origin and the smart field is correctly compute.

In the PackagingPerOrigin table, the (materialPerOrigin) => ... does not include the related data material & origin. The field is then not computed, thus only display the id.

On my end, switching

    get: (materialPerOrigin) => {
      return materialPerOrigin.idMaterial.name + ' ' + (materialPerOrigin.idOrigin ? materialPerOrigin.idOrigin.name : '');
    },

to

    get: async (materialPerOrigin) => {
      const materialPerOriginWithBelongsTo = await materialPerOrigin.findByPk(materialPerOrigin.id, { include: ['material', 'origin'] });
      return materialPerOriginWithBelongsTo.idMaterial.name + ' ' + (materialPerOriginWithBelongsTo.idOrigin ? materialPerOriginWithBelongsTo.idOrigin.name : '');
    },

Works as expected. It comes with the drawback of re-fetching the full materialPerOrigin, but that’s the best workaround I can propose to far (Until the proper fix is released).

Let me know if that helps :pray:

1 Like

Thanks!
I understand the issue and the workaround you are suggesting.

Sadly, it does not work on my end. I have a failure saying

findByPk is not a function

Do I have to update something?
It may be because I am not using forest-express-sequelize V8 ?

"forest-express-sequelize": "^7.9.4",

Sorry, I rewrote the example for your case and I didn’t notice this.

const materialPerOriginModel = require('../models').materialPerOrigin;
const materialPerOriginWithBelongsTo = await materialPerOriginModel.findByPk(materialPerOrigin.id, { include: ['material', 'origin'] });

:slight_smile:

1 Like

It is working perflectly!
Thanks a lot @jeffladiray ! :slight_smile:

1 Like