Multiple Duplicate Rows on the Forest Admin UI

Hi Forest Admin team,
I am facing duplicate user issues on the forest Admin UI due to some relationships if I add an Expense and Merchant it creates multiple duplicate users in the user table. Please look into the shared SS.
Please help me out with this problem.

Thanks

Hello @Supportpay,

We need more information to find the culprit.

  • Do you use forest-express-sequelize?
  • What is a Merchant? Can you share the schema of your DB to understand the relationships between Expense/Merchant/User?
  • If you only have one row in your DB forest admin only shows you one row with the default route but maybe you have changed something? Did you override the GET /users route?

Thanks for your response.

Kind regards,
Morgan

Hi @morganperre,

  1. Yes, we are using forest-express-sequelize.

  2. We would not be able to share the schema.
    You can understand the relation b/w these as

    Expense to merchant has a 1:1 relation i.e. 1 expense can have only 1 merchant

    Merchant to Expense has 1:n i.e. 1 merchant can have multiple expenses

    User to Expense has 1:n relation i.e. 1 user can have multiple expenses

    User to merchant 1:n .i.e. 1 user can have multiple merchants.

    Merchant to User 1:1 .i.e. 1 merchant can relate to 1 user.

  3. No, we did not override the GET /users route.

You can also see the shared SS, It shows only 1 user and 1 selected but on the UI It shows many duplicate users.

Thanks

Hi again @Supportpay,

Thanks for sharing those pieces of information. From an external point of view it like the /users route returns multiple times the same user, I wonder if the issue can come from a malformed request to your DB (missing groupBy clause for example that could explain why you have multiple time the same row).

  • Can you share the network call payload for the /users route? This can be really useful to validate my assumption.
  • Can you try running your back with an additional environment variable DEBUG=sequelize:sql* ? It will display the SQL queries done for each request. So you can share the SQL request made when you navigate to users view. :pray:

I’m looking forward to hearing from you again with your responses.

Kind regards,
Morgan

Hi @morganperre,
Here are the payload, preview, and SQL query screenshots, please check.





Thanks.

Hi @Supportpay :wave: can you share with us how your relations are formated with your sequelize models? :pray:

Hi @Arnaud_Moncel

These are the relationships between the user table and expense table:

  1. User.hasMany(models.expense, {
    foreignKey: {
    name: “giverIdKey”,
    field: “giver”,
    },
    as: “expense_list”,
    });

    Expense.belongsTo(models.user, {
    foreignKey: {
    name: “giverIdKey”,
    field: “giver”,
    },
    as: “giver_details”,
    });

  2. User.hasMany(models.expense, {
    foreignKey: {
    name: “childIdKey”,
    field: “child”,
    },
    as: “child_expenses”,
    });

    Expense.belongsTo(models.user, {
    foreignKey: {
    name: “childIdKey”,
    field: “child”,
    },
    as: “child_details”,
    });

  3. User.hasOne(models.expense, {
    foreignKey: {
    name: “createdByIdKey”,
    field: “created_by”,
    },
    as: “Expense Created By”,
    });

    Expense.belongsTo(models.user, {
    foreignKey: {
    name: “createdByIdKey”,
    field: “created_by”,
    },
    as: “created_by_details”,
    });

  4. User.hasOne(models.expense, {
    foreignKey: {
    name: “deletedOrVoidedByIdKey”,
    field: “deleted_or_voided_by”,
    },
    as: “Expenses deleted or Voided by”,
    });

    Expense.belongsTo(models.user, {
    foreignKey: {
    name: “deletedOrVoidedByIdKey”,
    field: “deleted_or_voided_by”,
    },
    as: “deleting_user_details”,
    });

  5. User.hasOne(models.expense, {
    foreignKey: {
    name: “originalPayerKey”,
    field: “original_payer”,
    },
    as: “original_payer_details”,
    });

    Expense.belongsTo(models.user, {
    foreignKey: {
    name: “originalPayerKey”,
    field: “original_payer”,
    },
    as: “original_payer_details”,
    });

  6. User.hasOne(models.expense, {
    foreignKey: {
    name: “recipientKey”,
    field: “recipient”,
    },
    as: “recipient_details”,
    });

    Expense.belongsTo(models.user, {
    foreignKey: {
    name: “recipientKey”,
    field: “recipient”,
    },
    as: “recipient_details”,
    });

  7. User.hasOne(models.expense, {
    foreignKey: {
    name: “lastModifiedByIdKey”,
    field: “last_modified_by_id”,
    },
    as: “Expense last modified by”,
    });

    Expense.belongsTo(models.user, {
    foreignKey: {
    name: “lastModifiedByIdKey”,
    field: “last_modified_by_id”,
    },
    as: “last_modified_by_details”,
    });

Here is the relationship between the user table and merchant table:

  1. User.hasOne(models.merchant, {
    foreignKey: “owner_id”,
    as: “merchant_details”,
    });

    Merchant.belongsTo(models.user, {
    foreignKey: “owner_id”,
    as: “owner”,
    });

Here is the relationship between the expense table and merchant table:

  1. Expense.belongsTo(models.merchant, {
    foreignKey: “merchant_id”,
    as: “merchant_details”,
    });

    Merchant.hasMany(models.expense, {
    foreignKey: “merchant_id”,
    as: “expenses”,
    });

Thanks

Hey @Supportpay,

Thanks for this. Can you also share child_physical_details Sequelize relationship? An potentially all User relationships?

Thanks,
Morgan

Hi @morganperre ,
I have already shared the details of the relations with the user and other child tables.
Please have a look on above shared relations.

Hey again,

We already tried to set up the same kind of relationships in a dummy project to reproduce your issue but we haven’t been able to reproduce nor understand it yet.


Looking at your logs, I saw relations to child_physical_details and child_education_information but it doesn’t appear in the relationship you have shared.

Our assumption is that one of your relationships is a malformed oneToMany (something like hasMany + hasOne that cause issues in Sequelize instead of hasMany/belongsTo). In this case, a LEFT JOIN could explain duplicated records.

You can hide all the fields (except username) in the UI, then put them one by one. This way we might have more information on the field that triggers the issue. :pray:

Let my know if you can do that.

Kind regards,
Morgan

Hi @morganperre can we connect over a meeting to better understand the issue? The user table is quite complex and has a lot of relations, I had shared the relations that I suspected to have the problem.
I can share the complete .forestadmin.schema.json if you want.

Hi, @morganperre tried hiding all the fields and kept the email field and there were no duplicates.
Then I unhide the Expense last modified by then I got 4 duplicates. Similarly got 2 duplicates with merchant_details.


this is the screenshot of the log for the Expense last modified by hiding/unhiding

In order to try to reproduce can you give us the version of forest-express-sequelize that you use? :pray:

Hi @Arnaud_Moncel ,
This “forest-express-sequelize”: “^8.0.0” is the version of forest-express-sequelize that we use.

Thanks

Are you sure you only have one row on expense.last_modified_by field containing your userId?
Have you setup this column has unique fk?

Hi @morganperre @Arnaud_Moncel,
I have removed all the “hasOne” and “hasMany” relations from the Users table which are not there in the Database and kept only the “belongsTo” relations in the other tables which belong to the users table. Now It’s working fine.

Thanks

2 Likes

Awesome news.

But it’s still weird since it should work for the other relationships.

Have a great experience on Forest Admin.

Kind regards,
Morgan

1 Like

Happy to hear that :smile:
Let us know if you have another problem.

1 Like