New Forest Admin agent Node.js - Adding relationships with other relationships that cause problems

Hello :wave:

Feature(s) impacted

collection.addOneToOneRelation()


collection.addOneToManyRelation()

Observed behavior

:warning: Important info: the relationships I add to my table can sometimes be null, i.e. there’s no data, this is deliberate.

When I add relationships to my beneficiaries table, I have a display problem that only occurs in certain cases.

Here is my code, which you can scroll down to see:

agent.customizeCollection('beneficiaries', collection => {
      // RELATIONS
      collection.addOneToOneRelation('np_contract', 'NP_contracts', {
        originKey: 'fk_beneficiaryId',
        originKeyTarget: 'id',
      });

      collection.addOneToOneRelation('np_subscription', 'NP_subscriptions', {
        originKey: 'fk_beneficiaryId',
        originKeyTarget: 'id',
      });
      
      collection.addOneToManyRelation('np_refundRequests', 'NP_refundRequests', {
        originKey: 'fk_beneficiaryId',
        originKeyTarget: 'id',
      });

      // collection.addOneToOneRelation('nv_contract', 'NV_contracts', {
      //   originKey: 'fk_beneficiaryId',
      //   originKeyTarget: 'id',
      // });

      collection.addOneToOneRelation('nv_subscription', 'NV_subscriptions', {
        originKey: 'fk_beneficiaryId',
        originKeyTarget: 'id',
      });

      // collection.addOneToManyRelation('nv_refundRequests', 'NV_refundRequests', {
      //   originKey: 'fk_beneficiaryId',
      //   originKeyTarget: 'id',
      // });

      // FIELDS
      collection.importField('user_email', { path: 'fk_user:email', readonly: true});
      collection.importField('user_phone', { path: 'fk_user:phone', readonly: true});
      collection.importField('user_firstname', { path: 'fk_user:firstname', readonly: true});
      collection.importField('user_status', { path: 'fk_user:status', readonly: true});
      collection.importField('user_lastname', { path: 'fk_user:lastname', readonly: true});
      collection.importField('user_gender', { path: 'fk_user:gender', readonly: true});
      collection.importField('user_discoveryProcess', { path: 'fk_user:discoveryProcess', readonly: true});
      collection.addField('np_subscription_amount', {
        columnType: 'Number',
        dependencies: ['np_subscription:rk_pspSubscriptionId'],
        getValues: (records, context) =>
          records.map(async r => {
            if (r.np_subscription !== null) {
              const invoices = await stripe.listInvoices({
                subscription: r.np_subscription.rk_pspSubscriptionId,
                status: 'paid'
              });
              if (invoices !== null) {
                return  invoices[0].amount_paid / 100;
              }
              return 0;
            }
            return 0;
          }),
      });
      collection.importField('np_contract_subscriptionDate', { path: 'np_contract:subscriptionDate', readonly: true});
      collection.importField('np_contract_startDate', { path: 'np_contract:subscriptionDate', readonly: true});
      collection.importField('np_plan_title', { path: 'np_contract:fk_plan:title', readonly: true});
      collection.importField('np_subscription_status', { path: 'np_subscription:status', readonly: true});
      collection.addField('np_coupon_code', {
        columnType: 'String',
        dependencies: ['np_subscription:rk_pspSubscriptionId'],
        getValues: (records, context) =>
          records.map(async r => {
            if (r.np_subscription !== null) {
              const invoices = await stripe.listInvoices({
                subscription: r.np_subscription.rk_pspSubscriptionId,
                status: 'paid'
              });
              return invoices[0].discount?.coupon?.name;
            }
            return null;
          }),
      });
      collection.addField('nv_subscription_amount', {
        columnType: 'Number',
        dependencies: ['nv_subscription:rk_pspSubscriptionId'],
        getValues: (records, context) =>
          records.map(async r => {
            if (r.nv_subscription) {
              const invoices = await stripe.listInvoices({
                subscription: r.nv_subscription?.rk_pspSubscriptionId,
                status: 'paid'
              });
              if (invoices !== null) {
                return invoices[0].amount_paid / 100;
              }
              return 0;
            }
            return 0;
          }),
      });
      // collection.importField('nv_contract_subscriptionDate', { path: 'nv_contract:subscriptionDate', readonly: true});
      // collection.importField('nv_contract_startDate', { path: 'nv_contract:startDate', readonly: true});
      // collection.importField('nv_product_name', { path: 'nv_contract:fk_product:name', readonly: true});
      // collection.addField('nv_contract_beneficiaries', {
      //   columnType: 'String',
      //   dependencies: ['nv_contract:beneficiaries'],
      //   getValues: (records, context) =>
      //     records.map(r => {
      //       if (r.nv_contract?.beneficiaries?.length > 0) {
      //         return true
      //       }
      //       return false;
      //     }),
      // });
      // collection.importField('nv_contract_status', { path: 'nv_contract:status', readonly: true});
      // collection.importField('nv_contract_adherentId', { path: 'nv_contract:rk_adherentId', readonly: true});
      // collection.importField('nv_contract_endDate', { path: 'nv_contract:endDate', readonly: true});
      // collection.addField('nv_subscription_type', {
      //   columnType: 'String',
      //   dependencies: ['nv_contract:filename'],
      //   getValues: (records, context) =>
      //     records.map(r => {
      //       if (r.nv_contract?.filename?.slice(0, 3) === "PV3") {
      //         return "PV3";
      //       }
      //       return '';
      //     }),
      // });
      // collection.addField('nv_coupon_code', {
      //   columnType: 'String',
      //   dependencies: ['nv_subscription:rk_pspSubscriptionId'],
      //   getValues: (records, context) =>
      //     records.map(async r => {
      //       if (r.nv_subscription !== null) {
      //         const invoices = await stripe.listInvoices({
      //           subscription: r.nv_subscription.rk_pspSubscriptionId,
      //           status: 'paid'
      //         });
      //         return invoices[0].discount?.coupon?.name;
      //       }
      //       return null;
      //     }),
      // });
      // collection.addField('nv_subscription_channel', {
      //   columnType: 'String',
      //   dependencies: ['nv_contract:filename'],
      //   getValues: (records, context) =>
      //     records.map(async r => {
      //       if (r.nv_contract?.filename?.slice(0, 3) === "PV3") {
      //         return "web";
      //       }
      //       return "app";
      //     }),
      // });

      // ACTIONS
    });

if I comment on all relationships starting with nv_, everything is displayed correctly
and you can see the details when you click on it

But if I uncomment the relation that start with nv_, I can no longer access certain details.

But the surprising thing is that when I click on those with data beginning with nv_ , it works.
For the example, I click on the one with Nv subscription amount at 40.1


Whereas if I click on one that is 0 I get the error

In the logs server I have this


and console.log I have this : 500

I’ve seen in the other tables that everything is fine, it’s only this beneficiaries table where when I add these relationships, I have this little problem

Expected behavior

The relations I add can all be displayed, even if the data is empty in the relation I’m adding.

Context

  • Project name: Nostrum Care v3
  • Team name: Op
  • Environment name: Local
  • Agent (forest package) name & version:
    @forestadmin/agent”: “^1.0.0”,
    @forestadmin/datasource-sequelize”: “^1.5.21”,
    @forestadmin/datasource-sql”: “^1.0.0”,
    “dotenv”: “^16.0.1”,
    “pg”: “^8.8.0”,
    “sequelize”: “^6.33.0”,
    “stripe”: “^14.17.0”
  • Database type: Postgresql

Thank you in advance for your help !!

Hello @jacques_liao,

Can you please share the exact version of the agent that you are running ? You provided the minimun version “^1.0.0” from the package.json, but you should be able to find the resolved version in your .lock file (package.lock, yarn.lock or similar).

I believe the issue that you are experiencing has been resolved in a more recent agent version, so if you could try to upgrade to the latest version :pray: and test in this context ?

Thanks

@Nicolas

Hello @Nicolas.M

I have this version :

"node_modules/@forestadmin/agent": {
  "version": "1.36.17",

If is not the correct version, what is the command to update the version of the forest admin agent version ?

Thanks

Hello @jacques_liao :wave:

So you will need to upgrade your version to the latest one. And also all @forestadmin/* packages to benefit from all our fixes :muscle:

That depends on your package manager (npm/yarn/pnpm), they provide commands to directly bump version.

But a simple way of doing it is to update your package.json manually and run a yarn install or npm install

You can found the latest version in there:

And if you want to resources on package manager comparisons.

Regards,
Morgan

Hello @morganperre @Nicolas.M,

I was able to update @forestadmin/agent to 1.43.0 with command

npm i @forestadmin/agent

forestadmin-schema.json :

  "meta": {
    "liana": "forest-nodejs-agent",
    "liana_version": "1.43.0",
    "liana_features": null,
    "stack": {"engine": "nodejs", "engine_version": "21.6.2"}
  }

package.json :

  "dependencies": {
    "@forestadmin/agent": "^1.43.0",
    "@forestadmin/datasource-sequelize": "^1.5.21",
    "@forestadmin/datasource-sql": "^1.0.0",
    "dotenv": "^16.0.1",
    "moment": "^2.30.1",
    "pg": "^8.8.0",
    "sequelize": "^6.33.0",
    "stripe": "^14.17.0"
  },

But I have this error in console.log


And this error in server

Hello @jacques_liao,

Sorry, so let’s try to deep dive into your issue.

You should be able to view the content of the error in your console by opening it. And you can also check the Network tab of the browser Developer tools to see the call (if you open the response you should have the Error object with more detail explainations).

Another question:

Kind regards,
Morgan

This is what I get as an error in the logs

And in network tab, I have this same error
But I don’t see where this 500 error could come from.

And to answer your question, no, I don’t use the log agent level. But I’ll look into it !

Thanks

1 Like

Let us know if you get more agent logs with this setup.

Kind regards,
Morgan

Hello @morganperre

I have this logs in server

I don’t see any errors in the log :confused:

Hello,

do you have any news about this problem :pray:?

Best regards

Hello @jacques_liao,
This is difficult to provide more guidance from us, with no stack trace from the agent or more details from the frontend errors.
Could you provide an HAR extract of the frontend rather than screenshots? this way we will be able to dig through the list of queries/replies, and maybe find details.

Did you try running the SQL query in the logs leading up to the errors, to see if one of them could be malformed or not working on your database ?

I’m surprised to see that a 404 error on agent side would result in a 500 error on frontend. Are you sure that those match ?

Thanks :pray:

Hello @Nicolas.M

Yes, I understand you completely. how can I send you the HAR extract data? as the content is too large for forest comunity

Yes, it works fine on our side with SQL commands

And yes, apart from this error I have nothing else.

Thanks in advance

How large is the HAR file ?
Please record just enough around the error encountered so that it is limited in size.
Please also note that it may contain sensitive info, so it is probably better to send it over through private message :pray:

Would you happen to work in an agent that is marked as production ? If so, then your stack traces will be removed, and you will need to ensure that you are working in a dev environment to ensure that your stack traces show up. :pray:

1 Like

Links removed for security

Yes indeed, I work in production.
I didn’t quite understand, i.e. aren’t the errors displayed in production?

Hello,
No, they are not, for security purposes.
The standard workflow is to work in a dev environment and solve the issues that you have there before commiting to production.

2 Likes

Thanks to this, I was able to correct the bugs
in fact, it was linked to an addField that was mismanaged on my side

2 Likes