Skip to content

Relations

Relations are the structural connectors between entities in your domain model. They define how data flows from one entity to another, and they directly determine how the mock runtime resolves nested fields in GraphQL queries. A well-defined set of relations produces predictable, nested API responses. A poorly configured set produces empty fields, incorrect shapes, or silent data loss.

This page covers every aspect of relation management: types, creation methods, direction and ownership semantics, cardinality consequences, and the causal chain from relation definition to runtime behavior.

Why Relations Matter

Every relation you define on the modelling board becomes a nested field in your GraphQL schema. When an API consumer queries a Customer and requests its orders, the runtime uses the relation definition to locate, join, and assemble the related Order records. Without a correctly configured relation, that nested field either returns an empty array or does not appear at all.

Relations are not decorative lines on a board. They are executable instructions for the query engine.

Relation Types

Mockomat supports three relation cardinalities. Each type determines the GraphQL return shape and the MongoDB lookup strategy the runtime uses at query time.

One-to-One (1:1)

A one-to-one relation connects exactly one record in the source entity to exactly one record in the target entity.

PropertyValue
ExampleUser -> Profile
GraphQL return typeSingle object (or null)
Runtime behaviorLookup returns at most one document

Use 1:1 relations when an entity has a single, tightly coupled companion. Typical cases include profile records, configuration objects, or billing details that always exist in a one-to-one correspondence with the parent.

Screenshot ws-relations-01-one-to-oneScreenshot ws-relations-01-one-to-one
ws-relations-01-one-to-oneMissing

One-to-one relation between User and Profile on the modelling board.

One-to-Many (1:n)

A one-to-many relation connects one record in the source entity to multiple records in the target entity.

PropertyValue
ExampleCustomer -> Order[]
GraphQL return typeArray of objects
Runtime behaviorLookup returns a collection of matching documents

This is the most common relation type. It represents ownership hierarchies: a customer owns orders, a project contains tasks, a category groups products. The parent entity exposes the children as a list field.

Screenshot ws-relations-02-one-to-manyScreenshot ws-relations-02-one-to-many
ws-relations-02-one-to-manyMissing

One-to-many relation between Customer and Order with array return.

Many-to-Many (m:n)

A many-to-many relation connects multiple records on both sides. Each record in the source entity can relate to multiple records in the target entity, and vice versa.

PropertyValue
ExampleProduct <-> Category
GraphQL return typeArray on both sides
Runtime behaviorImplicit join resolves through shared references

Many-to-many relations are appropriate when neither side exclusively owns the other. Products belong to multiple categories; categories contain multiple products. The runtime resolves these through an implicit join — no explicit junction table is required in your model.

Screenshot ws-relations-03-many-to-manyScreenshot ws-relations-03-many-to-many
ws-relations-03-many-to-manyMissing

Many-to-many relation between Product and Category.

Creating Relations

There are two ways to create a relation in Mockomat.

Drag-to-Connect on the Modelling Board

On the modelling board, each table card exposes connection points. To create a relation:

  1. Hover over a table card to reveal its connection handles.
  2. Click and drag from a handle on the source entity toward the target entity.
  3. Release over the target entity's connection area.
  4. A relation configuration dialog opens, where you specify cardinality, direction, and linking columns.

This method is fast and visually intuitive. It works well when you are designing the domain structure and want to see the spatial relationships between entities in real time.

Screenshot ws-relations-04-drag-to-connectScreenshot ws-relations-04-drag-to-connect
ws-relations-04-drag-to-connectMissing

Drag-to-connect interaction for creating a relation on the board.

Relation Editor in the Table Detail View

When you open a table in the detail view (by clicking on a table card or navigating from the tables and attributes configuration), a dedicated relation section allows you to create and manage relations:

  1. Click the add relation action in the relation section.
  2. Select the target entity from the entity list.
  3. Choose the cardinality (1:1, 1:n, or m:n).
  4. Define the direction — which entity is the parent and which is the child.
  5. Specify the linking columns that connect the two entities.

This method gives you precise control over every parameter and is preferable when you need to configure complex linking logic or review existing relations in detail.

Screenshot ws-relations-05-relation-editorScreenshot ws-relations-05-relation-editor
ws-relations-05-relation-editorMissing

Relation editor panel in the table detail view.

Direction and Ownership

Every relation has a direction. Direction determines which entity is the parent (the one that exposes the nested field) and which is the child (the one that appears as a nested object or array in the parent's response).

Parent and Child Semantics

  • The parent entity owns the relation and exposes the child as a queryable nested field.
  • The child entity is the target of the lookup. Its records are assembled and attached to the parent during query resolution.

For example, in a Customer -> Order[] relation, Customer is the parent. When you query customers, each customer record can include its related orders as a nested array. The direction establishes this nesting hierarchy.

Ownership vs. Reference

Not all relations represent ownership. Consider these two cases:

RelationPatternMeaning
Customer -> Order[]OwnershipA customer owns their orders. Deleting the customer conceptually orphans the orders.
Order -> PaymentMethodReferenceAn order references a payment method. The payment method exists independently.

Both are valid relations, but they carry different semantic weight. Ownership relations typically flow from aggregate root to dependent entity. Reference relations connect independent entities that happen to interact. Being explicit about this distinction improves the readability of your model and prevents confusion when reviewing nested query behavior.

Bidirectional Access

Depending on configuration, both entities in a relation may expose the counterpart as a nested field. In a Customer -> Order[] relation, the customer exposes orders. But the order can also expose its parent customer, enabling queries like:

graphql
query {
  orders(limit: 10) {
    id
    totalAmount
    customer {
      id
      name
    }
  }
}

Bidirectional access is controlled through the relation configuration. By default, the parent exposes the child. Reverse access must be explicitly enabled.

Screenshot ws-relations-06-direction-configScreenshot ws-relations-06-direction-config
ws-relations-06-direction-configMissing

Direction and bidirectional access settings in the relation editor.

Cardinality Consequences

Cardinality is not a cosmetic label. It directly controls the GraphQL return type and the runtime lookup strategy.

CardinalityGraphQL Field TypeLookup Strategy
1:1TargetEntity (single object or null)Match at most one document
1:n[TargetEntity] (array)Match all documents with the parent reference
m:n[TargetEntity] (array on both sides)Implicit join through shared references

Incorrect Cardinality

Setting the wrong cardinality leads to unexpected response shapes. For example:

  • A relation marked as 1:1 when the data is actually 1:n causes the runtime to return only the first matching record, silently discarding the rest.
  • A relation marked as 1:n when the data is actually 1:1 returns an array containing a single element, forcing consumers to unwrap an unnecessary list.

Review your cardinality choices carefully. If you are unsure whether a relation is 1:n or m:n, consider the future state of the domain, not just the current data shape.

Quality Checklist

Before finalizing any relation, verify the following:

  1. Ownership or reference? Does this relation represent real ownership (a customer owns their orders) or a cross-reference (an order references a payment method)?
  2. Direction clarity. Is it immediately obvious which entity is the parent and which is the child? Would a new team member understand the nesting hierarchy?
  3. Lookup behavior. When querying the parent, should child data be included by default? Should reverse lookups be available?
  4. Cardinality correctness. Is this truly 1:n, or could it evolve into m:n as the domain matures?
  5. Linking column validity. Do the specified linking columns exist and contain matching values in the underlying data?

Addressing these questions before moving to preview and hints validation prevents the most common relation-related issues.

Causality: Relations, Runtime Lookups, and Nested Queries

Understanding the causal chain from relation definition to query result is essential for diagnosing issues and building reliable mock APIs.

Stage 1: Relation Definition

You define a relation on the modelling board or in the table detail view. The definition includes source entity, target entity, cardinality, direction, and linking columns. This definition is stored as metadata alongside your project model.

Stage 2: Schema Generation

When the runtime activates, each relation becomes a nested field in the generated GraphQL schema. A Customer -> Order[] relation produces an orders field on the Customer type with return type [Order].

Stage 3: Query Resolution

When a consumer sends a query that includes a nested field, the runtime executes the following pipeline:

  1. Query planner identifies the nested field and locates the corresponding relation definition.
  2. MongoDB query builder constructs a $lookup aggregation stage using the linking columns from the relation.
  3. Result assembler attaches the lookup results to the parent documents in the correct shape (object for 1:1, array for 1:n and m:n).

Stage 4: Response Delivery

The assembled response is returned to the consumer as a standard GraphQL response. The nested structure mirrors the relation definitions exactly.

Screenshot ws-relations-07-causality-flowScreenshot ws-relations-07-causality-flow
ws-relations-07-causality-flowMissing

Causal flow from relation definition through runtime pipeline to nested query response.

Common Failure Modes

SymptomLikely CauseResolution
Nested field returns empty arrayWrong direction or missing linking columnVerify relation direction and confirm linking columns contain matching values
Nested field returns null on 1:1Target record does not exist for the given referenceCheck data integrity or adjust cardinality to optional
Unexpected single object instead of arrayCardinality set to 1:1 instead of 1:nUpdate cardinality in the relation editor
Deeply nested query times outExcessive relation depth (e.g., 4+ levels)Flatten the query or reduce nesting depth

Relation Depth

Each level of nesting in a GraphQL query traverses one relation and triggers one additional MongoDB lookup stage. Deeply nested queries (three or more levels) increase query complexity and execution time. Design your relations with query depth in mind — prefer flatter structures where possible, and use the preview and hints workflow to validate response times before exposing endpoints to consumers.

Summary

Relations are the mechanism that transforms a flat collection of entities into a connected domain model capable of serving nested GraphQL queries. Each relation carries precise semantics — type, direction, cardinality, and linking columns — that the runtime translates into MongoDB lookup operations. Correct relation configuration produces predictable, well-shaped API responses. Misconfigured relations produce silent data gaps that are difficult to diagnose without understanding the causal chain.

Use the modelling board for visual relation design, the tables and attributes detail view for precise configuration, the preview and hints workflow for validation, and the API design view to control how relation-derived fields are exposed to consumers.