4.3.5. Data Model Relationships

In this chapter, you’ll learn how to define relationships between data models in your module.

Important

Data model relationships are in active development and may change.

Use data model relationships when
  • You want to create a relation between data models in the same module.
Don't use data model relationships if
  • You want to create a relationship between data models in different modules. Use module links instead.

What is a Relationship Property?#

A relationship property is defined using relation methods, such as hasOne or belongsTo. It represents a relationship between two data models in a module.


One-to-One Relationship#

To define a one-to-one relationship, create relationship properties in the data models using the following methods:

  1. hasOne: indicates that the model has one record of the specified model.
  2. belongsTo: indicates that the model belongs to one record of the specified model.

For example:

1import { model } from "@medusajs/utils"2
3const User = model.define("user", {4  id: model.id().primaryKey(),5  email: model.hasOne(() => Email),6})7
8const Email = model.define("email", {9  id: model.id().primaryKey(),10  user: model.belongsTo(() => User, {11    mappedBy: "email",12  }),13})

The hasOne and belongsTo methods accept a function as a first parameter. The function returns the associated data model.

The belongsTo method also requires passing as a second parameter an object with the property mappedBy. Its value is the name of the relationship property in the other data model.

In the example above, a user has one email, and an email belongs to one user.


One-to-Many Relationship#

To define a one-to-many relationship, create relationship properties in the data models using the following methods:

  1. hasMany: indicates that the model has more than one records of the specified model.
  2. belongsTo: indicates that the model belongs to one record of the specified model.

For example:

1import { model } from "@medusajs/utils"2
3const Store = model.define("store", {4  id: model.id().primaryKey(),5  products: model.hasMany(() => Product),6})7
8const Product = model.define("product", {9  id: model.id().primaryKey(),10  store: model.belongsTo(() => Store, {11    mappedBy: "products",12  }),13})

In this example, a store has many products, but a product belongs to one store.


Many-to-Many Relationship#

To define a many-to-many relationship, create relationship properties in the data models using the manyToMany method.

For example:

1import { model } from "@medusajs/utils"2
3const Order = model.define("order", {4  id: model.id().primaryKey(),5  products: model.manyToMany(() => Product),6})7
8const Product = model.define("product", {9  id: model.id().primaryKey(),10  order: model.manyToMany(() => Order),11})

In this example, an order is associated with many products, and a product is associated with many orders.


Configure Relationship Property Name#

The relationship property methods accept as a second parameter an object of options. The mappedBy property defines the name of the relationship in the other data model.

As seen in previous examples, the mappedBy option is required for the belongsTo method.

For example:

1import { model } from "@medusajs/utils"2
3const User = model.define("user", {4  id: model.id().primaryKey(),5  email: model.hasOne(() => Email, {6    mappedBy: "owner",7  }),8})9
10const Email = model.define("email", {11  id: model.id().primaryKey(),12  owner: model.belongsTo(() => User, {13    mappedBy: "email",14  }),15})

In this example, you specify in the User data model’s relationship property that the name of the relationship in the Email data model is owner.

This is useful if the relationship property’s name is different than that of the associated data model.


Cascades#

When an operation is performed on a data model, such as record deletion, the relationship cascade specifies what related data model records should be affected by it.

For example, if a store is deleted, its products should also be deleted.

The cascades method used on a data model configures which child records an operation is cascaded to.

For example:

1import { model } from "@medusajs/utils"2
3const Store = model.define("store", {4  id: model.id().primaryKey(),5  products: model.hasMany(() => Product),6})7.cascades({8  delete: ["products"],9})10
11const Product = model.define("product", {12  id: model.id().primaryKey(),13  store: model.belongsTo(() => Store, {14    mappedBy: "products",15  }),16})

The cascades method accepts an object. Its key is the operation’s name, such as delete. The value is an array of relationship property names that the operation is cascaded to.

In the example above, when a store is deleted, its associated products are also deleted.

Was this chapter helpful?