Phantom Relationship fields

Hello! I signed up for the Directus Community because I’m prototyping Directus locally in order to make sure it will suit our requirements. I have the dockerized local version (Directus 11.13.2 currently)

I have exported some data from a very old Drupal 7 install and I’ve gotten it to import cleanly at times, but haven’t been able to get relationships working.

I have collection called “minisites” and another called “menus” and a many to many junction called “minisites_menus”.

During my attempts to get ‘menus’ to return when I request a minisite (http://localhost:8055/items/minisites/16?fields=*&deep[menus][menu_links][_limit]=999 I’ve struggled. I never do see any menus, though the db structure seems to indicate everything is aligned.

I’ve tried deleting and recreating and get random directus_relationships entries like minisites_menus_1and menus_minisites . I set the many-to-many relationships up in the UI and it seems fine at first. Right now, during my import (a custom script using the API), I get:

data: {
      errors: [
        {
          message: 'select "menus"."id", "menus"."status", "menus"."sort", "menus"."user_created", "menus"."date_created", "menus"."user_updated", "menus"."date_updated", "menus"."title", "menus"."alias", "menus"."pages", "menus"."minisites" from "menus" where "menus"."id" = $1 order by "menus"."sort" asc limit $2 - column menus.minisites does not exist',
          extensions: { code: 'INTERNAL_SERVER_ERROR' }
        }
      ]
    }

I’m guessing it’s seeing those relationships (minisites.menus and menus.minisites) but this returns nothing:

select * from directus_relations where many_field IN (‘minisites’) or one_field IN (‘minisites’);

This is under my Menus collection:

When I open it, it doesn’t show any relationship info

[I tried to add another image here showing that when I click that and “edit”, it doesn’t show anything about relationships, it’s just a regular field; however, I am only allowed to add one image because I’m new here]

Here’s the db for both tables:

CREATE TABLE menus(
    id SERIAL NOT NULL,
    status varchar(255) NOT NULL DEFAULT 'draft'::character varying,
    sort integer,
    user_created uuid,
    date_created timestamp with time zone,
    user_updated uuid,
    date_updated timestamp with time zone,
    title varchar(255) NOT NULL DEFAULT NULL::character varying,
    alias varchar(255) NOT NULL,
    pages integer,
    PRIMARY KEY(id),
    CONSTRAINT menus_user_updated_foreign FOREIGN key(user_updated) REFERENCES directus_users(id),
    CONSTRAINT menus_user_created_foreign FOREIGN key(user_created) REFERENCES directus_users(id),
    CONSTRAINT menus_pages_foreign FOREIGN key(pages) REFERENCES pages(id)
);
CREATE UNIQUE INDEX menus_alias_unique ON public.menus USING btree (alias);
CREATE INDEX menus_alias_index ON public.menus USING btree (alias);
CREATE INDEX menus_title_index ON public.menus USING btree (title);
CREATE TABLE minisites(
    id SERIAL NOT NULL,
    status varchar(255) NOT NULL DEFAULT 'draft'::character varying,
    sort integer,
    user_created uuid,
    date_created timestamp with time zone,
    user_updated uuid,
    date_updated timestamp with time zone,
    title varchar(255) NOT NULL,
    slug varchar(255) DEFAULT NULL::character varying,
    description text,
    landing_page integer,
    PRIMARY KEY(id),
    CONSTRAINT minisite_user_updated_foreign FOREIGN key(user_updated) REFERENCES directus_users(id),
    CONSTRAINT minisite_user_created_foreign FOREIGN key(user_created) REFERENCES directus_users(id),
    CONSTRAINT minisite_landing_page_foreign FOREIGN key(landing_page) REFERENCES pages(id)
);
CREATE INDEX minisite_title_index ON public.minisites USING btree (title);
CREATE INDEX minisite_slug_index ON public.minisites USING btree (slug);
CREATE TABLE minisites_menus(
    id SERIAL NOT NULL,
    user_created uuid,
    date_created timestamp with time zone,
    user_updated uuid,
    date_updated timestamp with time zone,
    minisite integer,
    menu integer,
    PRIMARY KEY(id),
    CONSTRAINT minisites_menus_user_created_foreign FOREIGN key(user_created) REFERENCES directus_users(id),
    CONSTRAINT minisites_menus_user_updated_foreign FOREIGN key(user_updated) REFERENCES directus_users(id),
    CONSTRAINT minisites_menus_minisite_foreign FOREIGN key(minisite) REFERENCES minisites(id),
    CONSTRAINT minisites_menus_menu_foreign FOREIGN key(menu) REFERENCES menus(id)
);

EDIT: I dumped the schema to yaml and see this:

- collection: menus
    field: minisites
    type: alias

And I found it:

select id, collection, field, special, interface, options, hidden from directus_fields where collection in ('menus','minisites') and field in ('menus','minisites')
id collection field special interface options hidden
115 menus minisites m2m list-m2m null false
117 minisites menus m2m list-m2m null false

But, it’s not really a “field” in the DDL (see above, which are still accurate). So, Directus’ relational system appears to want to find it as a real “field” in the db table for the collection, but it is just a relationship definition, no?


Once in awhile, everything aligns and I can import, but I’m hoping to get back the menus with minisite result and I never get anything. I’ve used a lot of URLs like http://localhost:8055/items/minisites/16?fields=*&deep[menus][menu_links][_limit]=999 but I might be doing that wrong.

I’ve also completely deleted the db and started fresh several times now which takes a bit and I think I’m prone to mistakes.

Does anyone have any advice on what to check next?

Thanks!

Hello @ha17

When setting up a many-to-many (M2M) relationship in Directus, you typically have two main collections and one junction (bridge) collection that connects them.

For example:

  • minisites → contains fields like id and name
  • menus → contains fields like id and link
  • minisites_menus → the junction table with id, minisites_id, and menus_id as foreign keys

In this setup, the minisites collection will automatically get a virtual field called menus once the relationship is configured in the Data Model. This field represents all related menus connected through the junction collection.

To fetch a single minisite along with all its related menus, you can use a request like this:

/items/minisites/1?fields=*,menus.*,menus.menus_id.*&deep[menus][_limit]=-1

The response will look like this:

{
  "id": 1,
  "name": "xyz",
  "menus": [
    {
      "id": 1,
      "minisites_id": 1,
      "menus_id": {
        "id": 1,
        "link": "https://example.com"
      }
    },
    {
      "id": 2,
      "minisites_id": 1,
      "menus_id": {
        "id": 2,
        "link": "https://another-link.com"
      }
    }
  ]
}

Also make sure you have access to all the fields and collections when fetching the data.