Usage of ManyToOne relation returns null in TypeGraphQL - node.js

For learning, I made a project testing out TypeGraphql, together with TypeORM. I have a User and Book entity, where I want to have a created_by field on the Book entity.
#ObjectType()
#Entity()
export class Book extends BaseEntity {
#Field(() => ID)
#PrimaryGeneratedColumn()
readonly id: number;
#Field({ nullable: true })
#Column({ nullable: true })
name: string;
#Field(() => User)
#ManyToOne(() => User)
#JoinColumn({ name: 'created_by' })
created_by: User;
// #RelationId((orthodontist: Orthodontist) => orthodontist.created_by)
// createdById: number;
}
#ObjectType()
#Entity()
export class User extends BaseEntity {
#Field(() => ID)
#PrimaryGeneratedColumn()
id: number;
#Field({ nullable: true })
#Column({ nullable: true })
first_name?: string;
#Field({ nullable: true })
#Column({ nullable: true })
last_name?: string;
#Field()
#Column({ unique: true })
email: string;
#Column()
password: string;
#Field(() => [Book!])
#OneToMany(() => Book, book => book.created_by)
created_books: Book[];
}
For my resolver, it simply looks like this, which I am properly loading as the docs say.
#Resolver(Book)
export class OrthodontistResolver {
#Query(() => [Book])
books(): Promise<Book[]> {
return Book.find();
}
}
When I go into my GraphQL playground, and query something like this:
{
books {
name,
id,
}
}
It all works and returns the right data. However, when I try to use the created_by field like this:
{
orthodontists {
name,
id,
created_by {
id
}
}
}
It gives me the following error:
Cannot return null for non-nullable field Book.created_by.
I made sure the relation exists in the database, and set up correctly with it's FK's. Where does this come from though? How can I fix this? I did try using the #RelationId decorator, as seen in the first code example. It unfortunately didn't work.
EDIT:
There is only one book in the database, where the created_by field is not null.

Change your books resolver to return the relationship created_by when using find operation:
#Resolver(Book)
export class OrthodontistResolver {
#Query(() => [Book])
books(): Promise<Book[]> {
return Book.find({
relations: ["created_by"],
});
}
}

Related

TypeOrm update Entity not updating related one

I have this entity:
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
email: string;
#Column()
password: string;
#Column({ default: false })
activated: boolean;
#OneToOne(() => UserAnag, (userAnag) => userAnag.user)
useranag: UserAnag;
}
and this related entity
#Entity()
export class UserAnag {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column()
surname: string;
#OneToOne(() => User, (user) => user.useranag, {
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
})
#JoinColumn()
user: User;
and this is my update function:
async update(id: number, attrs: Partial<UpdateUserDto>) {
const user = await this.findById(id);
if (!user) {
throw new NotFoundException('User not found');
}
if (attrs.useranag) {
const useranag = Object.assign(user.useranag, attrs.useranag);
Object.assign(user, attrs);
user.useranag = useranag;
} else {
Object.assign(user, attrs);
}
return this.repo.save(user);
}
my findById function
if (!id) {
return null;
}
const user = await this.repo.find({
where: { id: id },
relations: { useranag: true },
});
return user[0];
}
If i debug this, i can see that the userEntity is correctly updated and also the return have the correct object updated but on database, only User entity is correctly updated, not Useranag entity.
I try alo setting eager on Useranag but have the same problem. Database is updated only in User not in Useranag
Additional info:
I'm logging the query and before update , select only id and userId on useranag entity that are obviously equal to the original and no update query was launched
The cascade syntax is different. You can either set it as cascade: true
or a list of operations to cascade
#OneToOne(() => User, (user) => user.useranag, {cascade: true})
#JoinColumn()
user: User;
#OneToOne(() => User, (user) => user.useranag, {cascade: ['update', 'delete']})
#JoinColumn()
user: User;
Source: https://orkhan.gitbook.io/typeorm/docs/relations#cascades
I have solved the problem. I made confusion between onUpdate e cascade: ['update']
The correct way that i find to update my related entity is to set
cascade: ['update'] in the entity i will update, not in the related entity.
So the correct code is:
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
email: string;
#Column()
password: string;
#Column({ default: false })
activated: boolean;
#OneToOne(() => UserAnag, (userAnag) => userAnag.user, {
cascade: ['update'],
})
useranag: UserAnag;
}
and
#Entity()
export class UserAnag {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column()
surname: string;
#Column()
psn: string;
#Column()
discord: string;
#Column()
drivernumber: number;
#OneToOne(() => User, (user) => user.useranag, {
onDelete: 'CASCADE',
})
#JoinColumn()
user: User;
}

How to Select Some Fields From Relations in Typeorm Relations

I need to Select Some fields from relations in Nest.js TypeOrm .
For Example My Entity is :
#Entity()
export class Chat {
#PrimaryGeneratedColumn()
public id: number;
#Column()
public orderId: number;
#Column({ default: ChatStatus.Active })
public status: ChatStatus;
#Column()
public userId: number;
#ManyToOne(() => User, (user) => user.chats, { nullable: true })
#JoinColumn({ name: 'userId' })
public user: User;
}
Any In My Service :
async findAll(dataSearch) {
return await this.chatRepository.find({
relations: ['user'],
});
}
I Want Just Select "name" , "avatar" from user relation but This select all Columns.
Thanks
#Column({ type: "timestamp", default: () => 'CURRENT_TIMESTAMP',
select: false
})
updated_at: Timestamp;
Example
#Column({ type: "timestamp", default: () => 'CURRENT_TIMESTAMP', select: false })

Is there a way to get all Entity records through a custom pivot table

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

Nestjs TypeORM syntax error at or near "AND"

I am building a UserService class in my system, and declaring which should be a simple 'find' method, but I'm receiving the error as shown in the image bellow:
This is my service method:
#Injectable()
export class UsersService {
...
async findByRA(academicRegister: string) {
return await this.userRepository.findOne({
where: { academicRegister: academicRegister },
});
}
...
}
This is my controller:
#Controller('users')
export class UsersController {
...
#Get('ra/:ra')
findByRa(#Param('ra') ra: string) {
return this.usersService.findByRA(ra);
}
...
}
This is my User entity, and if I change eager to false, the error does not happen, however I don't get the data from the child entities, which I need
#Entity()
export class User {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
#ApiProperty({ enum: UserRole, enumName: 'UserRole' })
userRole: UserRole;
#Column()
academicRegister: string;
#Column()
password: string;
#OneToOne(() => Coordinator, (coordinator) => coordinator.user, {
eager: true,
nullable: true,
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
coordinator?: Coordinator;
#OneToOne(() => Monitor, (monitor) => monitor.user, {
eager: true,
nullable: true,
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
monitor?: Monitor;
#CreateDateColumn()
creationDate: Date;
#DeleteDateColumn()
deletionDate?: Date;
#Column({ nullable: true })
deletedBy?: string;
}
These are the related columns in the child entities:
export class Coordinator {
...
#Column({ nullable: true, unique: true })
userId: string;
#OneToOne(() => User, (user) => user.coordinator, {
orphanedRowAction: 'nullify',
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
user: User;
...
}
export class Monitor {
...
#Column({ nullable: true, unique: true })
userId: string;
#OneToOne(() => User, (user) => user.monitor, {
orphanedRowAction: 'nullify',
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
user: User;
...
}
Eager relations are loaded automatically each time you load entities
from the database.
When You will be loading your Coordinator or Monitor entity you don't need to have manually call for your relations it will be done automatically.
You must be accessing your entities in wrong way.

typeorm save in joined cloumn

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 });

Resources