One To Many relationship properties not functioning as expected. Cannot Retrieve List Members from Group records – NestJS TypeORM

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()

Leave a Comment