I am defining entity fields in my NestJS project. I have ManyToOne realtion that is defined successfully. I have trouble finding the right way to define OneToMany relation to fit the syntax I used for other relation.
import {Entity,Column, PrimaryColumn, ManyToOne,JoinColumn,OneToMany} from "typeorm";
import { Account } from "./account.entity";
import { Balance } from "./balance.entity";
import { BaseEntity } from "./base.entity";
#Entity()
export class MainEntity extends BaseEntity {
#PrimaryColumn({
type: "varchar",
name: "id",
unique: true
})
id: string;
#ManyToOne(() => Account, { nullable: true })
#JoinColumn({
name: "account_id",
referencedColumnName: "id"
})
account: Account;
#OneToMay relation needs to be connected to the Balance entity and mappedBy paymentDevice field in it.
My try:
#OneToMany(() => Balance, ...)
balances: Balance[]
I am in NestJs and typescript so this is challenging for me.
Generally, TypeORM relations used in NestJS are simple and dev-friendly. The code which you've written defines parameters which are already predefined.
For example,
#PrimaryColumn({
type: "varchar",
name: "id",
unique: true
})
This exact parameters is what defined by
#PrimaryColumn() // unique: true
id: string //varchar, name: id
So you can have the code just like below. For Account Entity,
#Entity()
export class Account {
#PrimaryColumn()
id: string;
#ManyToOne(type => Balance, balance => balance.id)
balance: Balance;
}
For Balance Entity
#Entity()
export class Balance {
#PrimaryColumn()
id: string;
#OneToMany(type => Account, account => account.id)
#JoinColumn({name: "account_id"})
// defining this is also optional because by default,
// the referenced foreign key is named as <column_name>_id or account_id
account: Account;
}
This will create a many-to-one relationship on Account and OneToMany on Balance entity. For more such examples, Refer: https://orkhan.gitbook.io/typeorm/docs/many-to-one-one-to-many-relations
Related
I have two entities, Teacher and Student with a many to many relationship, connected using a join table called TeacherStudents. I want to query multiple teachers and the related students under each teacher, but i want to be able to limit how many teachers are fetched per query and also limit how many related students are fetched per teacher.
My entities:
Teacher.ts
#Entity()
export class Teacher extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
#OneToMany(() => TeacherStudents, (ts) => ts.teacher)
studentConn: Promise<TeacherStudents[]>;
}
Student.ts
#Entity()
export class Student extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#CreateDateColumn({ type: 'timestamp' })
createdAt: Date;
#OneToMany(() => TeacherStudents, (ts) => ts.student)
teacherConn: Promise<TeacherStudents[]>;
}
Then I have a separate join table to connect both entities
TeacherStudents.ts
#Entity()
export class TeacherStudents {
#PrimaryColumn()
teacherId: number;
#PrimaryColumn()
studentId: number;
#ManyToOne(() => Teacher, (teacher) => teacher.studentConn)
#JoinColumn({ name: 'teacherId' })
teacher: Promise<Teacher>;
#ManyToOne(() => Student, (student) => student.teacherConn)
#JoinColumn({ name: 'studentId' })
student: Promise<Student>;
}
So far I have been able to get this working
query.ts
async getTeachers(limit:number){
const maxLimit = Math.min(16, limit)
const teachers = await AppDataSource.getRepository(Teacher)
.createQueryBuilder('teacher')
.innerJoin('teacher.studentConn', 'studentConn')
.innerJoin('studentConn.student', 'student')
.select('teacher', 'student')
.take(maxLimit)
.getMany();
return teachers;
}
The issue with this is that "take" only applies on the parent (Teacher) object. I want to know how I can apply "take" on the child (Student) for each Teacher returned by the query.
Basically I want to paginate for each Teacher and it's relation Student.
I am trying to create a tweet bookmarking feature in my project. Where a user can save tweets to view them later. I am able to hit an endpoint and save a bookmark table record given a userId and tweetId. I'm having trouble figuring out how to return all bookmarked tweets using typeorm. One user can have many bookmarks.
I have the three following entities in a mysql database
tweet.entity.ts
#Entity()
export class Tweet {
#PrimaryGeneratedColumn()
public id?: number;
#Column('text')
public text: string;
#ManyToOne(() => User, (user: User) => user.tweets)
public user: User;
#OneToMany(() => Comment, (comment: Comment) => comment.tweet)
public comments: Comment[];
}
user.entity.ts
#Entity()
class User {
#PrimaryGeneratedColumn()
public id?: number;
#Column({ unique: true })
public email: string;
#OneToMany(() => Tweet, (tweet: Tweet) => tweet.user)
public tweets: Tweet[];
}
bookmark.entity.ts
#Entity()
export class Bookmark {
#PrimaryGeneratedColumn()
public id?: number;
#Column()
public userId: number;
#Column()
public tweetId: number;
}
One solution using query builder:
const items = await dataSource
.createQueryBuilder(tweet, "tweet")
.innerJoin("bookmark", "bookmark", "bookmark.tweetId = tweet.id")
.where("bookmark.userId = :userId", { userId: userId })
.getMany();
You can also declare a many-to-many relation between Tweet and User with Bookmark as pivot table:
user.entity.ts
#ManyToMany(type => Tweet)
#JoinTable({
name: "bookmarks", // pivot table name
// Custom column name
// joinColumn: {
// name: "userId",
// referencedColumnName: "id"
// },
// inverseJoinColumn: {
// name: "tweetId",
// referencedColumnName: "id"
// }
})
bookmarks: Tweet[];
Usage:
userRepository.find({
relations: ["bookmarks"],
})
More info: https://github.com/typeorm/typeorm/blob/master/docs/relations.md#jointable-options
Consider a base entity as below:
export abstract class Notification {
#PrimaryGeneratedColumn()
id: number;
#Column({type: "date",nullable: false})
seenAt: Date;
#Column({ type: "integer", nullable: false })
priority: number;
}
and two child entities as below:
#Entity()
export class NotificationType1 extends Notification {}
and
#Entity()
export class NotificationType2 extends Notification {}
Is there a way to find all rows in NotificationType1 and NotificationType2 using a query to the parent class like this?
SELECT * FROM NOTIFICATION;
This query return 0 rows, although there are records in NotificationType1 and NotificationType2 tables.
You should be able to Select from the superclass and retrieve all the records with something like this:
import {getConnection} from "typeorm";
const user = await getConnection().createQueryBuilder()
.select("notification")
.from(Notification, "notification");
You also need to change your abstract class to #TableInheritance to leverage Single Table Inheritance.
This Code:
export abstract class Notification {
#PrimaryGeneratedColumn()
id: number;
#Column({type: "date",nullable: false})
seenAt: Date;
#Column({ type: "integer", nullable: false })
priority: number;
}
Would become:
#Entity()
#TableInheritance({ column: { type: "varchar", name: "type" } })
export class Notification {
#PrimaryGeneratedColumn()
id: number;
#Column({type: "date",nullable: false})
seenAt: Date;
#Column({ type: "integer", nullable: false })
priority: number;
}
And the Child Entity:
#ChildEntity()
export class NotificationType1 extends Notification {}
The docs have on single table inheritance.
in my project i have two entity, naturalist(user) and comment entity
i create relation between them, how to save reciever_id (joined cloumn) in comment entity
this is my comment entity
#Entity()
export class Comments extends BaseEntity {
#PrimaryGeneratedColumn()
id: string
#ManyToOne(
type => Naturalist,
naturalist => naturalist.comments
)
#JoinColumn({
name: 'naturalist_id',
})
naturalist: Naturalist
#Column({ nullable: true, default: '' })
text?: string
#Column({ nullable: true, default: '' })
sender_id?: string
}
naturalist(my user) entity
#Entity()
export class Naturalist extends BaseEntity {
#PrimaryGeneratedColumn()
id: number
#Column()
user_id: string
#OneToMany(
type => Comments,
comment => comment.naturalist
)
comments: Comments[]
}
DTO contains
{
receiver_id: '2cc2f359-821c-4940-99ae-7386576d861b',
text: 'string',
id: 'e0464049-d1d9-474a-af5b-815805aa1c4b'
}
i want to save receiver_id to my comment entity
if I understand correctly your needs,
I think you need an insert method to do this:
await entityManager.insert(Comments, { naturalist: { id: '2cc2f359-821c-4940-99ae-7386576d861b' } as Naturalist });
I'm using TypeORM in Node.JS and would like to use the entity inheritance to implement a BaseRecord:
export abstract class BaseRecord {
#CreateDateColumn({type: 'timestamp'})
public created_at: Date;
#UpdateDateColumn({type: 'timestamp'})
public updated_at: Date;
#ManyToOne(type => User, user => user.records_created)
public created_by: User
#ManyToOne(type => User, user => user.records_updated)
public updated_by: User
}
Which I would like to extend other entities by. This works as expected when removing the #ManyToOne relationship:
#Entity()
export class Address extends BaseRecord {
#PrimaryGeneratedColumn()
public id: number;
#Column({ nullable: true, type: "text" })
public alias: string;
#Column({ type: "text" })
public street_1: string;
#Column({ nullable: true, type: "text" })
public street_2: string;
#Column({ type: "text" })
public city: string;
#Column({ type: "text" })
public state: string;
#Column({ type: "text" })
public zip_code: string;
#Column(type => GeoLocation)
public geo_location: GeoLocation
}
Has anyone run into this or a method to inherit entity and have ManyToOne relationships?
I suggest using composition over inheritance with an Embedded Entity
An embedded column is a column which accepts a class with its own columns and merges those columns into the current entity's database table.
You can use as many columns (or relations) in embedded classes as you need. You even can have nested embedded columns inside embedded classes.
import {Column} from "typeorm";
export class Assigned {
#ManyToOne(type => User, user => user.records_created)
public created_by: User
#ManyToOne(type => User, user => user.records_updated)
public updated_by: User
}
export class Dated {
#CreateDateColumn({type: 'timestamp'})
public created_at: Date;
#UpdateDateColumn({type: 'timestamp'})
public updated_at: Date;
}
then use it
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import {Assigned} from "./Assigned";
import {Dated} from "./Dated";
#Entity()
export class Address extends BaseRecord {
// ...Other columns
#Column(type => Assigned)
assigned: Assigned;
#Column(type => Dated)
dated: Dated;
}
You can use as many columns (or relations) in embedded classes as you need.
You even can have nested embedded columns inside embedded classes.