# Relationships  ## What is a relationship?  A relationship in Gadget is a connection between two models that allows you to link records of one model with the other. Relationships are created using relationship fields like belongs to, has one, has many, and has many through. They enable easy data fetching in the API and help in organizing data in a normalized fashion. ## Types of relationships  There are four relationship types available in Gadget: * belongs to relationships are used to express that a record references zero or one other parent record. belongs to represents the side of a one-to-one or one-to-many relationship which stores the `id`. * has one relationships are part of one-to-one relationships between two models. * has many relationships are part of many-to-one relationships between models. * has many through relationships are used when describing a many-to-many relationship between two models. A has many through requires an in-between join model that has one row per unique combination of the two related models. ### Belongs To relationships  The belongs to relationship establishes a link between a record of one model and a record of another model. It is used when one record is directly associated or categorized under another record. By defining a belongs to relationship, you create a connection that allows easy navigation and retrieval of associated records. A belongs to relationship can be used to represent a parent-child relationship or one side of a has many or has one relationship. Specifically, belongs to is the side that stores the `id` value of the relationship. For this reason, you can liken the belongs to relationship to a table storing a FOREIGN KEY in an SQL database. For example, if you have a **Blog Post** model representing each post to a blog, you might also have a **Comment** model that allows readers to discuss each post. In this case, each comment pertains directly to one post, and so we say the comment _belongs to_ the post and create a belongs to relationship from the **Comment** model to the **Post** model. ```mermaid graph LR B[Comment] C[Comment] D[Comment] A[Blog Post] B --->|Belongs To| A C --->|Belongs To| A D --->|Belongs To| A ``` Each **Comment** record will then have an associated **Post** object. Different comments can have different posts, but each comment has only one post. belongs to relationships create a one-way relationship from the model they are on to the related model. If you want to access the relationship from the other way around, to say, access all the comments for a given post, you would need to create a has one or has many relationship on the other model. In the example above, a belongs to on the **Comment** model will create a `post` field on each `Comment` object in the GraphQL API that returns that comment's parent `Post` record. `Comment` records will also have a `postId` field if you need to access just the ID of a comment's parent post. Here's what the setup looks like in Gadget: Other examples of belongs to relationships include: * a **Blog Post** record belonging to an **Author** record in a blogging app * a **Product Image** record belonging to an **Product** record in an ecommerce app * a **Person** record belonging to an **Company** record in a CRM app * a **User** record belonging to a **Team** record in a multi-tenant SaaS app ### Has One relationships  has one relationships set up a connection between one record of a model to one record of another model. has one relationships should be used any time two models are always siblings and always only have zero or one records on the other side of the relationship. The has one relationship does not have a direct equivalent in SQL because it doesn't store anything -- it just sets up useful API fields for accessing and mutating a related record. has one relationship fields work together with the belongs to field to create a one-to-one relationship. The belongs to side stores the `id` of the has one side, whereas the has one side creates a field on the GraphQL API query that returns the related record on the belongs to side. For example, we might have a **User** model in an application that may or may not have set up a billing relationship with the company running the app. In this instance, each user can only have one **Billing Account**, and each billing account corresponds to exactly one user. We have a one-to-one relationship, and so we add a belongs to to the **Billing Account** model and a has one to the **User** model: ```mermaid graph LR B[User] C[Billing Account] B --->|Has One| C C --->|Belongs To| B ``` Here, our **User** model has one **Billing Account**, but nothing referencing **Billing Account** is stored in the **User** record. Instead, the has one of the **User** model will create a `billingAccount` field on each `User` object in the GraphQL API that returns the related billing account records. **Billing Account** would have a **User** column storing the associated record's `id`. has one relationships tend to be somewhat rare. If the two models that have a one-to-one relationship have the same lifecycle, such that they are created and deleted at the same time, it can be annoying to manage them as two separate models. It's often easier to just combine them into the same model and not have any relationship at all. If the two models in a one-to-one relationship have different lifecycles, has one can be useful to allow one model to come and go independently of the other. It can also be difficult to determine which side of the relationship should get the has one and which side should get the belongs to. Usually, it is best to select the model that tends to exist for longer as the owner of the has one. That way, when the model that gets deleted more often gets deleted, you don't have to update the other model that is still around because the belongs to field's value has just been deleted. If there isn't really a pattern between when the two models get created and deleted, then it tends to not matter which side gets which relationship type. Here's what the setup looks like in Gadget: The has one and belongs to combination can be used to create non-strict one-to-one relationships. This is best illustrated with an example. Referring back to the **Billing Account** and **User** models, a billing account can only have one user associated to it, because the belongs to (billing) side only has room for one `id`. However, no such restriction exists on the has one (user) side, and its possible for a user to create multiple billing accounts when they should only have one. This can be fixed by adding a uniqueness validation on the belongs to field that points to the has one side. ### Has Many relationships  has many relationships set up a connection between one record of a model to many records of another model. has many relationships should be used anytime one record owns or categorizes several records of another model. Like has one, adding a has many doesn't have a direct equivalent in SQL because it doesn't store anything -- it just sets up useful API fields for accessing and mutating the list of related records. belongs to and has many work together to represent the one-to-many relationship. has many relationship fields create a field on the GraphQL API object of the related model which is used to query the belongs to side, and the belongs to side stores the `id` of the has many. In the example of a blog app, we might have a **Blog Post** model and a **Comment** model where each comment _belongs to_ a post, and so the **Comment** model would have a belongs to relationship pointing to the **Post** model. In this case, we'd want each post record to have many comments so that several different users could write comments. We say that the post _has many_ comments, and create a has many relationship on the **Post** model linking the **Comment** model so that in the API, the list of comments from each post can be fetched easily. ```mermaid graph LR B[Comment] C[Comment] D[Comment] A[Blog Post] A --->|Has Many| B A --->|Has Many| C A --->|Has Many| D ``` In this example, the **Comments** model will store the **Blog Post** `id`. The has many on **Blog Post** will create a `comments` field on each `BlogPost` object in the GraphQL API. This represents a query which scans all `Comments` objects to find references to the current post, and returns them all as a list. Here's what the setup looks like in Gadget: Another example of a has many relationship could be: * an **Author** record having many **Blog Post** records in a blogging app ### Has Many Through relationships  has many through relationships set up a _many-to-many_ relationship between two models. has many through relationships should be used when both sides of a relationship have many records on the other side, or there's no clear owner in a relationship between two models. Because they represent _many-to-many_ relationships, there is no correct place to put an id reference on either of the related models, as that would only let us model a relationship to one record instead of to many. For this reason, Gadget uses a third, intermediate model, where each record of this third model represents one instance of the relationship between the first two models. Because of this, has many through relationships require more configuration than usual to set up. For example, let's consider a school registration system where we have a **Student** model representing each person enrolled and a **Course** model representing each subject being taught. Students need to enroll in many courses because they take more than one course at once, and courses are taught by teachers who can teach more than one student at once. Each side of this relationship has more than one related record on the other side, so we call it a _many-to-many_ relationship and use a has many through to represent it. We create a third model that sits between Student and Course called **Registration**, which will have one record for each course that each student has enrolled in. ```mermaid graph LR A[Student] B[Student] C[Student] D[Course] E[Course] F[Course] A --> R1[Registration] --> D A --> R2[Registration] --> E A --> R3[Registration] --> F B --> R4[Registration] --> D B --> R5[Registration] --> E B --> R6[Registration] --> F C --> R7[Registration] --> D C --> R8[Registration] --> E C --> R9[Registration] --> F ``` We can demonstrate this more concretely with data in the student and course relations: If one student enrolls in three courses, that will generate three **Registration** records representing those three enrollments. If a second student then enrolls in the same three courses, that will generate three _more_ Registration records. These Registration records have independent lifecycles, so to model a student dropping a course, we'd delete the relevant Registration record and leave the Student and Course records as they were. In the example above, a has many through on the **Student** model will create a `courses` field on each `Student` object in the GraphQL API that returns that students' list of registered `Course` records using the **Registration** model to build the list underneath. Here's what the setup looks like in Gadget: another example of a has many through relationship could be: * a **Category** record having many **Product** records through **Categorization** records in an ecommerce app. Since products can be in many categories, and categories can have many products, there must be an intermediate through model to model the many-to-many relationship. ## Adding a relationship  As an example, let's create a relationship between a Post model and a Comment model through a has many relationship. On the `Post` model, we start by adding a new field called `Comments`, and assigning it the has many _Children_ field type. Note that we call this field `Comments`, as this field represents zero-to-many `Comment` records associated with a given `Post` record. Then we select `Comment` which will be the child model of `Post`: Once we've selected the `Comment` model, we can instantly create a belongs to field to reflect this relationship on the `Comment` model: And with that, our relationship between `Post` and `Comment` is created on both models. If you look at the data shape of our `Comment` model in the API reference, you'll notice that there is a `postID` field present, even though you didn't manually create this field. When a relationship is created between two models, Gadget automatically creates an ID field to store the foreign keys needed to link instances of the related models to one another. ```graphql type Comment { """ The time at which this record was first created. Set once upon record creation and never changed. Managed by Gadget. """ createdAt: DateTime! """ The globally unique, unchanging identifier for this record. Assigned and managed by Gadget. """ id: GadgetID! """ The time at which this record was last changed. Set each time the record is successfully acted upon by an action. Managed by Gadget. """ updatedAt: DateTime! post: Post postId: GadgetID """ Get all the fields for this record. Useful for not having to list out all the fields you want to retrieve, but slower. """ _all: JSONObject! } ``` ### Using a relationship in the API  Once the relationship exists, you can set a belongs to relationship by passing `{ _link: "" }` for the relationship field. You can then read related data back with `select`. ```typescript const post = await api.post.create({ title: "Relationships in Gadget", }); // create a comment that belongs to the post const comment = await api.comment.create({ body: "This post explains relationships clearly", post: { _link: post.id }, }); // read the comment and post, given the comment id const commentWithPost = await api.comment.findById(comment.id, { select: { id: true, body: true, post: { id: true, title: true, }, }, }); // read the post and comments, given the post id const postWithComments = await api.post.findById(post.id, { select: { id: true, title: true, comments: { edges: { node: { id: true, body: true, }, }, }, }, }); ``` Or use the GraphQL API: ```graphql mutation CreateComment($comment: CreateCommentInput) { createComment(comment: $comment) { success errors { message } comment { id body post { id title } } } } ``` ```json { "comment": { "body": "This post explains relationships clearly", "post": { "_link": "123" } } } ``` In this example, `comment.post` reads the parent record through the belongs to relationship, and `post.comments.edges[].node` reads the child records through the has many relationship. Use `_link` when you are setting a single existing related record on the belongs to side of a relationship. For the inverse side, you generally update the child model's belongs to field, or use [nested actions](https://docs.gadget.dev/guides/actions/code#nested-actions-and-execution-order) on the parent model to create or re-link child records. When you need to replace or synchronize an entire child list on a has many relationship, use the [`_converge` nested action](https://docs.gadget.dev/guides/actions/code#converge-actions). For has many through relationships, create or update the join model records instead of linking the top-level field directly.