Search code examples
postgresqltypeorm

TypeORM - postgresSQL / saving data in the DB


So, i'm new into this typeORM thing, and actually also new into postgresSQL DB, and there's something i couldn't undertand about typeORM and making relations between tables.

My Question: So, i have two entities, User and Post. When you create a post, we store the user ( creator of the post ) in the DB using @JoinColumn, and when i go to users table, i can see the name of that field (username), but, inside User entity, we have an array of Posts, but, that field doesn't appear in the postgres DB, so, when i create a relation, @ManyToOne and @OneToMany, what data stores in the DB and which don't ? Besides that, when i fetch stuff, i can fetch the array, but, does that array is store in the DB or what ? I'm kinda confused with this, so, now let me show you the code

User entity

import {
  Entity as TOEntity,
  Column,
  Index,
  BeforeInsert,
  OneToMany
} from "typeorm";
import bcrypt from "bcrypt";
import { IsEmail, Length } from "class-validator";
import { Exclude } from "class-transformer";

import Entity from "./Entity";
import Post from "./Post";

@TOEntity("users")
export default class User extends Entity {
  constructor(user: Partial<User>) {
    super();
    Object.assign(this, user);
  }

  @Index()
  @IsEmail(undefined, { message: "Must be a valid email address" })
  @Length(5, 255, { message: "Email is empty" })
  @Column({ unique: true })
  email: string;

  @Index()
  @Length(3, 200, { message: "Must be at leat 3 characters long" })
  @Column({ unique: true })
  username: string;

  @Exclude()
  @Length(6, 200, { message: "Must be at leat 3 characters long" })
  @Column()
  password: string;

  @OneToMany(() => Post, post => post.user)
  posts: Post[];

  @BeforeInsert()
  async hashedPassword() {
    this.password = await bcrypt.hash(this.password, 6);
  }
}

Post entity

import {
  Entity as TOEntity,
  Column,
  Index,
  BeforeInsert,
  ManyToOne,
  JoinColumn,
  OneToMany
} from "typeorm";

import Entity from "./Entity";
import User from "./User";
import { makeid, slugify } from "../util/helpers";
import Sub from "./Sub";
import Comment from "./Comment";

@TOEntity("posts")
export default class Post extends Entity {
  constructor(post: Partial<Post>) {
    super();
    Object.assign(this, post);
  }

  @Index()
  @Column()
  identifier: string; // 7 Character Id

  @Column()
  title: string;

  @Index()
  @Column()
  slug: string;

  @Column({ nullable: true, type: "text" })
  body: string;

  @Column()
  subName: string;

  @ManyToOne(() => User, user => user.posts)
  @JoinColumn({ name: "username", referencedColumnName: "username" })
  user: User;

  @ManyToOne(() => Sub, sub => sub.posts)
  @JoinColumn({ name: "subName", referencedColumnName: "name" })
  sub: Sub;

  @OneToMany(() => Comment, comment => comment.post)
  comments: Comment[];

  @BeforeInsert()
  makeIdAndSlug() {
    this.identifier = makeid(7);
    this.slug = slugify(this.title);
  }
}

How the User entity looks as a table in the DB

enter image description here

So, as you can see, there's no field with name posts ( which is weird, because as i already said, if i can fetch that, where is that data if i can't see it in the DB )

Now, let me show you Post entity

enter image description here

What i want to understand: So, we have the relationship between tables, know, i tried to search stuff in order to understand that, but i couldn't find anything, so, if you can help me with this mess, i would really aprecciate that, so, thanks for your time !


Solution

  • Let's take this section and try to understand piece by piece:

    @ManyToOne(() => User, user => user.posts)
    @JoinColumn({ name: "username", referencedColumnName: "username" })
    user: User;
    

    1. @ManyToOne(() => User, user => user.posts):

    • @ManyToOne: This annotation tells typeORM that Post entity is going to have a many to one relationship. From the postgres DB point of view, this means that posts table is going to have a new column (foreign key) which points to a record in some other table.

    • () => User: This is called definition of the target relationship. This helps typeORM to understand that the target of the relationship is User entity. For postgres DB, this means the foreign key in posts table is going to reference a row in users database

    • user => user.posts: This is called the inverse relationship. This tells typeORM that the related property for the relationship in User entity is posts. From the postgres DB point of view, this has no meaning. As long as it has the foreign key reference, it can keep the relationship between the two tables.

    2. @JoinColumn({ name: "username", referencedColumnName: "username" }):

    • @JoinColumn: In this scenario, this annotation helps typeORM to understand the name of the foreign key column in posts table and the name of the referenced column in users table

    • name: "username": This is the name of the column in posts table which is going to uniquely identify a record in users table

    • referencedColumnName: "username": This is the name of the column in users table which is going to be referenced by the foreign key username in posts table.


    inside User entity, we have an array of Posts, but, that field doesn't appear in the postgres DB

    The array of Posts is there for the typeORM to return you an array of linked posts. It is not needed by postgres DB to contain the relationship.

    when i create a relation, @ManyToOne and @OneToMany, what data stores in the DB and which don't

    Whatever property you decorated using @Column will be there in the table as it is. And for the relationships, only the foreign key will be saved. As an example, when you save a Post entity, it will save only the relevant columns in that entity + username foreign key.

    when i fetch stuff, i can fetch the array, but, does that array is store in the DB or what ?

    When you query User entity, typeorm uses the annotations to join users table with posts table and return you the posts with the user you searched. But in database, it saves users and posts data in their respective tables and uses username foreign key to keep the relationship between them.


    I hope this helps you to understand what happens. Cheers 🍻 !!!