Is there anyone willing to help me understand TypeORM and Nestjs? I keep getting this unbearably annoying error “Cannot read properties of undefined (reading 'id')
” and I’m sure it has something to do with relations but cant figure out how to get it to work.
I have a Group entity that has a OneToMany relationship with my User entity (i.e. each user can only belong to one group at a time, but group can have many users.)
What I have been trying to do is create two route handlers. One, that uses a group id and user id to adds a user to a group’s member list and another route handler, that given a group id, returns the list of members from that group.
My getMembersList
method throws a Cannot read properties of undefined (reading 'id')
when I attempt to return my group.members
array. From what I understand, typeorm doesnt expose certain properties on an entity unless explicitly stated (e.g.relations: {members: true}
) and that could be the reason the id property is undefined for what im guessing is regarding the user, probably because I didnt expose my User’s group
property, but honestly I dont know why that would be the case when Im not querying my database for any specific users.
Likewise, in my addMember
method I can apparently add a user to the Groups members list if I go through the User entity (e.g. user.group = group;
) but I cant seem to add a user to the members list through the Group entity (i.e. group.members.push(user)
). When I try to add the user via group.members.push(user)
typeOrm does not associate the Users groupId
column with the corresponding group (i.e. when I inspect my User table the groupId
column is null)
I honestly just don’t get it..
Below are some of the relevant code snippets. (I removed the imports for brevity)
group.entity.ts
@Entity()
export class Group {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => User, (user) => user.group, { cascade: true })
members: User[];
}
user.entity.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
email: string;
@Column()
password: string;
@ManyToOne(() => Group, (group) => group.members)
group: Group;
}
groups.controller.ts
@Patch('/add-member/:id')
@Serialize(GroupListDto)
async addMember(@Param('id') groupId, @Body() body) {
return this.groupsService.addMember(+groupId, body);
}
@Get('/get-members/:id')
@Serialize(GroupListDto)
async getMembersList(@Param('id') groupId: string) {
return this.groupsService.getMembersList(+groupId);
}
group-list.dto.ts
export class GroupListDto {
@Expose()
id: number;
@Expose()
name: string;
@Expose()
@Type(() => UserDto)
user: UserDto;
}
export class UserDto {
@Expose()
id: number;
@Expose()
email: string;
}
groups.service.ts
async getMembersList(groupId: number) {
const group = await this.groupsRepository.findOne({
where: { id: groupId},
relations: { members: true },
});
if (!group) {
throw new NotFoundException('Group not found');
}
console.log('GET MEMBERS');
console.log(group.members);
return group.members;
}
async addMember(groupId: number, body: GroupListDto) {
const res = await this.entityManager.transaction(async (entityManager) => {
const group = await this.groupRepository.findOne({
where: { id: groupId},
relations: { members: true },
});
if (!group) {
throw new NotFoundException('Group not found');
}
// Assigning the group via the members array doesnt seem to work
group.members.push(user);
await this.entityManager.save(group);
console.log(group.members);
// Assigning the group via the user seems to work?
// const user = await this.usersRepository.findOne({
// where: { id: body.user.id },
// relations: { group: true },
// });
// user.group = group;
// await this.entityManager.save(user);
});
return res;
}
sample requests
### add member 1 to group 2 (addUser)
PATCH http://localhost:3000/groups/add-member/2
Content-Type: application/json
{
"user": {"id": 1}
}
### Get all Users in group 2 (getMemberList)
GET http://localhost:3000/groups/get-members/2
Any advice is very much appreciated
I tried adding @JoinTable() to my group property on the User entity. I tried adding it to the members property on the Group entity. I tried adding it separately and to both at the same time.
I tried adding { cascade: true } to my group property on the User entity. I tried adding it to the members property on the Group entity. I tried adding it separately and to both at the same time.
I tried changing the DTOs.
I tried with EntityManager
and with groupsRepository
I tried running within entityManager.transaction()
and without it.
I tried adding a user to the member list by assigning the group to users.group.
When I console.log()
the objects. the id properties the error complains about apparently exist. The members
list is populated with the user I pushed
into the array. likewise, the Group
values are displayed and I see an id
value. Same goes for the User
. The error Cannot read properties of undefined (reading 'id')
occurs when I run this.entityManager.save()