From bbed7af027868bff2bc7d0a02d6c1be1a901878a Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 12 Dec 2024 17:32:49 +0200 Subject: [PATCH] docs: document many-to-many with extra columns (#10586) --- .../data-models/manage-relationships/page.mdx | 58 +++++++++++++++++++ .../data-models/relationships/page.mdx | 51 ++++++++++++++++ www/apps/book/generated/edit-dates.mjs | 4 +- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx b/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx index 60abbb7708860..bba9dbe814b5e 100644 --- a/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx +++ b/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx @@ -100,6 +100,12 @@ In the example above, you pass the `store_id` property when creating or updating ## Manage Many-to-Many Relationship + + +If your many-to-many relation is represented with a [pivotEntity](../relationships/page.mdx#many-to-many-with-custom-columns), refer to [this section](#manage-many-to-many-relationship-with-pivotentity) instead. + + + ### Create Associations When you create a record of a data model that has a many-to-many relationship to another data model, pass an array of IDs of the other data model's records in the relation property. @@ -176,6 +182,58 @@ This keeps existing associations between the product and orders, and adds a new --- +## Manage Many-to-Many Relationship with pivotEntity + + + +If your many-to-many relation is represented without a [pivotEntity](../relationships/page.mdx#many-to-many-with-custom-columns), refer to [this section](#manage-many-to-many-relationship) instead. + + + +If you have a many-to-many relation with a `pivotEntity` specified, make sure to pass the data model representing the pivot table to [MedusaService](../../modules/service-factory/page.mdx) that your module's service extends. + +For example, assuming you have the [Order, Product, and OrderProduct models from the previous chapter](../relationships/page.mdx#many-to-many-with-custom-columns), add `OrderProduct` to `MedusaService`'s object parameter: + +```ts highlights={["4"]} +class HelloModuleService extends MedusaService({ + Order, + Product, + OrderProduct +}) {} +``` + +This will generate Create, Read, Update and Delete (CRUD) methods for the `OrderProduct` data model, which you can use to create relations between orders and products and manage the extra columns in the pivot table. + +For example: + +```ts +// create order-product association +const orderProduct = await helloModuleService.createOrderProducts({ + order_id: "123", + product_id: "123", + metadata: { + test: true + } +}) + +// update order-product association +const orderProduct = await helloModuleService.updateOrderProducts({ + id: "123", + metadata: { + test: false + } +}) + +// delete order-product association +await helloModuleService.deleteOrderProducts("123") +``` + +Since the `OrderProduct` data model belongs to the `Order` and `Product` data models, you can set its order and product as explained in the [one-to-many relationship section](#manage-one-to-many-relationship) using `order_id` and `product_id`. + +Refer to the [service factory reference](!resources!/service-factory-reference) for a full list of generated methods and their usages. + +--- + ## Retrieve Records of Relation The `list`, `listAndCount`, and `retrieve` methods of a module's main service accept as a second parameter an object of options. diff --git a/www/apps/book/app/learn/fundamentals/data-models/relationships/page.mdx b/www/apps/book/app/learn/fundamentals/data-models/relationships/page.mdx index c288f4ab33444..150da2901acc1 100644 --- a/www/apps/book/app/learn/fundamentals/data-models/relationships/page.mdx +++ b/www/apps/book/app/learn/fundamentals/data-models/relationships/page.mdx @@ -200,6 +200,57 @@ The pivot table has columns with foreign keys pointing to the primary key of the ![Diagram illustrating the relation between order and product records in the database](https://res.cloudinary.com/dza7lstvk/image/upload/v1726734269/Medusa%20Book/many-to-many_fzy5pq.jpg) +### Many-To-Many with Custom Columns + +To add custom columns to the pivot table between two data models having a many-to-many relationship, you must define a new data model that represents the pivot table. + +For example: + +export const manyToManyColumnHighlights = [ + ["5", "products", "Many-to-many relation to the `Product` data model."], + ["6", "pivotEntity", "Specify the data model representing the pivot table."], + ["12", "orders", "Many-to-many relation to the `Order` data model."], + ["15", "OrderProduct", "Data model that represents the pivot table between orders and products."], + ["17", "order", "Relation to the Order data model."], + ["20", "product", "Relation to the Product data model."], + ["23", "metadata", "Extra column in the pivot table."] +] + +```ts highlights={manyToManyColumnHighlights} +import { model } from "@medusajs/framework/utils"; + +export const Order = model.define("order_test", { + id: model.id().primaryKey(), + products: model.manyToMany(() => Product, { + pivotEntity: () => OrderProduct + }) +}) + +export const Product = model.define("product_test", { + id: model.id().primaryKey(), + orders: model.manyToMany(() => Order) +}) + +export const OrderProduct = model.define("orders_products", { + id: model.id().primaryKey(), + order: model.belongsTo(() => Order, { + mappedBy: "products" + }), + product: model.belongsTo(() => Product, { + mappedBy: "orders" + }), + metadata: model.json().nullable() +}) +``` + +The `Order` and `Product` data models have a many-to-many relationship. To add extra columns to the created pivot table, you pass a `pivotEntity` option to the `products` relation in `Order` (since `Order` is the owner). The value of `pivotEntity` is a function that returns the data model representing the pivot table. + +The `OrderProduct` model defines, aside from the ID, the following properties: + +- `order`: A relation that indicates this model belongs to the `Order` data model. You set the `mappedBy` option to the many-to-many relation's name in the `Order` data model. +- `product`: A relation that indicates this model belongs to the `Product` data model. You set the `mappedBy` option to the many-to-many relation's name in the `Product` data model. +- `metadata`: An extra column to add to the pivot table of type `json`. You can add other columns as well to the model. + --- ## Set Relationship Name in the Other Model diff --git a/www/apps/book/generated/edit-dates.mjs b/www/apps/book/generated/edit-dates.mjs index 0ee94396832a8..4cc507ffbc315 100644 --- a/www/apps/book/generated/edit-dates.mjs +++ b/www/apps/book/generated/edit-dates.mjs @@ -38,10 +38,10 @@ export const generatedEditDates = { "app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2024-12-04T07:37:59.822Z", "app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2024-12-11T08:36:08.282Z", "app/learn/fundamentals/data-models/write-migration/page.mdx": "2024-11-11T15:27:59.794Z", - "app/learn/fundamentals/data-models/manage-relationships/page.mdx": "2024-10-28T04:22:21.328Z", + "app/learn/fundamentals/data-models/manage-relationships/page.mdx": "2024-12-12T14:23:26.254Z", "app/learn/fundamentals/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00", "app/learn/fundamentals/modules/options/page.mdx": "2024-11-19T16:37:47.253Z", - "app/learn/fundamentals/data-models/relationships/page.mdx": "2024-12-09T15:54:30.304Z", + "app/learn/fundamentals/data-models/relationships/page.mdx": "2024-12-12T14:08:50.686Z", "app/learn/fundamentals/workflows/compensation-function/page.mdx": "2024-12-06T14:34:50.384Z", "app/learn/fundamentals/modules/service-factory/page.mdx": "2024-10-21T13:30:21.371Z", "app/learn/fundamentals/data-models/primary-key/page.mdx": "2024-10-21T13:30:21.368Z",