Browse all documentation

Join field

Expose an access-controlled inverse view of documents that point to the current collection.

Use field.Join for the inverse side of a singular relationship. It queries documents that point to the current document instead of storing a second synchronized ID list.

In the admin

A populated Articles in this category Join field in the Ridu admin showing the related article row.

The table is computed from forward relationships, so the category stores no duplicate list of post IDs.

Smallest working example

content/categories.go
var Categories = ridu.Collection{
  Slug: "categories",
  Fields: []field.Definition{
    field.Text("name", field.Required()),
    field.Join("posts", "posts", "category"),
  },
}

var Posts = ridu.Collection{
  Slug: "posts",
  Fields: []field.Definition{
    field.Text("title", field.Required()),
    field.Relationship("category", field.To("categories")),
  },
}

The constructor arguments are the output field name, target collection, and target relationship path. That path must identify a singular, non-polymorphic relationship back to the source collection.

Configure the admin view

content/categories.go
field.Join(
  "posts", "posts", "category",
  field.JoinLimit(20),
  field.JoinColumns("title", "status", "updatedAt"),
  field.JoinDefaultSort("-updatedAt"),
  field.JoinAllowCreate(true),
)

JoinLimit is between 1 and 100. Columns, sorting, and inline-create availability describe the admin table; target read/create access still applies. Joins must live at a collection root and are not supported on globals.

The value appears in generated output but never in create/update input. Reads apply target access, hooks, localization, and field redaction. Select output fields to omit an expensive join when a consumer does not need it. Use SDK mutateJoin for an explicit atomic addition/removal; it updates the target documents’ forward relationships through validation and access.

Common mistakes

  • Do not create and manually synchronize a second forward relationship.
  • JoinAllowCreate(true) is an affordance, not permission.
  • Changing the target/on path can be a relationship-shape migration even though the Join itself is response-only.

See field.Join and Relationships and joins.