Relationship defined in old SugarCRM 6.5.25 instance not functioning in SuiteCRM 8.9.1

I am currently testing the upgrade path for SugarCRM 6.5.25 → SuiteCRM 7.x → SuiteCRM 8.9.1 and have come across a strange relationship issue with the Campaigns and Prospects (Targets) module.

A custom one-to-one relationship was defined to allow setting a campaign for individual targets. I understand the core logic is to use target lists for campaigns, however this was set up before I was tasked with upgrading the instance.

The issue this is causing in SuiteCRM 8.9.1 is that when viewing the list view of the campaigns module, instead of 132 campaigns displaying as they would in SugarCRM, We now see 53,270 campaigns, the vast majority of which are duplicate records that point to the same id. This is also the case for all of the modules that use the campaign relate field, so searching for a campaign to relate to the record is impossible.

My question to everyone is, is there a way to prevent the list view, and related module relate fields, from displaying all the duplicates? I cannot remove the relationship as this would remove important data that is reported on.

Here is the relationship info:

Here is the PHP definition:

<?php
// created: 2025-12-30 18:46:58
$dictionary["prospects_campaigns_1"] = array (
  'true_relationship_type' => 'one-to-one',
  'from_studio' => true,
  'relationships' =>
  array (
    'prospects_campaigns_1' =>
    array (
      'lhs_module' => 'Prospects',
      'lhs_table' => 'prospects',
      'lhs_key' => 'id',
      'rhs_module' => 'Campaigns',
      'rhs_table' => 'campaigns',
      'rhs_key' => 'id',
      'relationship_type' => 'many-to-many',
      'join_table' => 'prospects_campaigns_1_c',
      'join_key_lhs' => 'prospects_campaigns_1prospects_ida',
      'join_key_rhs' => 'prospects_campaigns_1campaigns_idb',
    ),
  ),
  'table' => 'prospects_campaigns_1_c',
  'fields' =>
  array (
    0 =>
    array (
      'name' => 'id',
      'type' => 'varchar',
      'len' => 36,
    ),
    1 =>
    array (
      'name' => 'date_modified',
      'type' => 'datetime',
    ),
    2 =>
    array (
      'name' => 'deleted',
      'type' => 'bool',
      'len' => '1',
      'default' => '0',
      'required' => true,
    ),
    3 =>
    array (
      'name' => 'prospects_campaigns_1prospects_ida',
      'type' => 'varchar',
      'len' => 36,
    ),
    4 =>
    array (
      'name' => 'prospects_campaigns_1campaigns_idb',
      'type' => 'varchar',
      'len' => 36,
    ),
  ),
  'indices' =>
  array (
    0 =>
    array (
      'name' => 'prospects_campaigns_1spk',
      'type' => 'primary',
      'fields' =>
      array (
        0 => 'id',
      ),
    ),
    1 =>
    array (
      'name' => 'prospects_campaigns_1_ida1',
      'type' => 'index',
      'fields' =>
      array (
        0 => 'prospects_campaigns_1prospects_ida',
      ),
    ),
    2 =>
    array (
      'name' => 'prospects_campaigns_1_alt',
      'type' => 'alternate_key',
      'fields' =>
      array (
        0 => 'prospects_campaigns_1campaigns_idb',
      ),
    ),
  ),
);

This is not a data corruption issue but a join explosion caused by the relationship design.

Although the relationship is marked as true_relationship_type = one-to-one, it is actually implemented as a many-to-many relationship with a join table. In SuiteCRM 8.x, Campaigns listviews and relate popups will JOIN that table, so each Campaign is returned once per linked Prospect, resulting in tens of thousands of duplicate rows pointing to the same campaigns.id.

How to fix / mitigate:

  1. Remove the relate field from Campaigns listview/search/popup layouts (Studio → Campaigns). This prevents the JOIN and immediately removes duplicates.

  2. Correct the data model: this is logically many Prospects → one Campaign. Use a Campaign relate field on Prospects (FK) instead of a M2M join table.

  3. (Last resort) Force DISTINCT / GROUP BY campaigns.id in a custom listview override — not recommended long-term.

The relationship itself isn’t “broken”; it’s just incompatible with how SuiteCRM 8 builds list and popup queries.

Thank you for your reply, however the main issue I see with this approach is that I will lose all of those relationships that already exist. Any ideas on how I can mitigate this issue?

Hello Josh,

depending on what you’d like to do and how you’d like to do the migration.
In systems which are that old, I often see old code / fields / logic that doesn’t apply anymore since businesses change over time.
In some cases, I’d do a simple data migration via the API instead trying to keep the same DB and upgrade the system via the standard upgrade / migration path.
That is an option - you’ll have to see, whether that is a good one for your scenario.

Bastian,

I have been able to mitigate all but a few issues, this and a couple other issues I have posted about, this one being the only one that I can tell is related to the upgrade and not a SuiteCRM regression.

Doing an API migration would have been far more complicated than doing the upgrade in this instance.

I think now that I have removed the relationship (but did not delete the table) and added a custom Targets → Campaigns relate field, I can develop a quick script to query from the defunct relationship table and update the records with the associated campaign.

Thanks everyone for the help!

2 Likes

Sounds good.

Yes, if this is the very last bit, with a script that is often best / easiest.