How do I search in the postgresql using Typeorm and return the mutated value for relation? - postgresql

I have a User entity with a Role relationship in an application Nestjs.
#Entity()
class User {
...
#ManyToOne(() => Role, {
eager: true,
})
role?: Role;
}
#Entity()
export class Role extends EntityHelper {
#PrimaryColumn()
id: number;
#Column()
name?: string;
}
when I want get users from the DB I do:
this.usersRepository.find({
relations: {
role: true,
},
})
and I get data like this:
{ id: 1, name: "John", role: { id: 2, name: "user" }}
but I don't want to get the role as an object, I just want the name from this
Example:
{ id: 1, name: "John", role: "user" }
So, my question is how can I get the relation and return only the value of { ... role: "user" }?

You can achieve it by using QueryBuilder:
this.usersRepository.createQueryBuilder('User')
.innerJoinAndSelect('User.role', 'Role')
.select(['Role.name as role', 'User.id as id'])
.getRawMany()

Related

Nested populate not working for mikro-orm

I'm using mikro-orm with nest.js, I have Users, Roles and Permissions entities. I need to select user by id with it's role and permissions from database. I'm using the following code to select user with everything:
this._userRepo.findOne({ $or: [{ email }] }, { populate: ['role', 'role.permissions'] })
I need the result to look like the following code example, but permissions are not selected:
{
id: 1,
email: 'john.doe#inter.net',
firstName: 'john',
lastName: 'Doe',
...
role: {
id: 21,
name: 'Moderator',
permissions: [
{ id: 1, name: 'Create' },
{ id: 2, name: 'Update' },
{ id: 3, name: 'Delete' },
]
}
}
Here's how my entities and schema looks like:
// user.entity.ts
#Entity({ tableName: 'users' })
export class UserEntity {
#PrimaryKey() id: number;
#Property() email: string;
#Property() firstName: string;
#Property() lastName: string;
...
#ManyToOne(() => RoleEntity) role: ref<RoleEntity, 'id'>;
constructor(role: RoleEntity) {
this.role = ref(role);
}
}
// role.entity.ts
#Entity({ tableName: 'roles' })
export class RoleEntity {
#PrimaryKey() id: number;
#Property() name: string;
...
#ManyToMany(() => PermissionEntity) permissions = new Collection<PermissionEntity>(this);
}
// permission.entity.ts
#Entity({ tableName: 'permissions' })
export class PermissionEntity {
#PrimaryKey() id: number;
#Property() name: string;
}
And there's roles_permissions table generated in database:
|role_entity_id|permission_entity_id|
|--------------|--------------------|
| 1 | 1 |
How can I solve this issue?
After torturing for several hours, I found that I was missing some properties to be specified in #ManyToMany relation.
So, I changed my RoleEntity to:
#Entity({ tableName: 'roles' })
export class RoleEntity {
#PrimaryKey() id: number;
#Property() name: string;
...
#ManyToMany({
entity: () => PermissionEntity,
owner: true,
pivotTable: 'roles_permissions',
joinColumn: 'role_entity_id',
inverseJoinColumn: 'permission_entity_id',
hidden: true,
})
permissions = new Collection<PermissionEntity>(this);
}
And now I can select role with it's permissions from database.

Create foreign key that references another schema

I have a multi tenant app which uses sequelize-typescript. Each time a new user is created, a new schema is created for them.
There's only one table in public schema - "Users".
Each tenant schema has "Roles" and "UserRoles" as a junction table.
I want UserRoles to reference Users in a public schema, not in a tenant schema. How can I achieve that?
user model
#Table({ paranoid: true })
export default class User extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#Column(DataType.STRING)
name: string;
#BelongsToMany(() => Role, () => UserRole)
roles: Role[];
role model
#Table({ paranoid: true })
export default class Role extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#Column(DataType.STRING)
name: string;
#BelongsToMany(() => User, () => UserRole)
users: User[];
}
user-role model
#Table({ paranoid: true, freezeTableName: true })
export default class UserRole extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#ForeignKey(() => Role)
#Column(DataType.BIGINT)
roleId: number;
#Unique
#ForeignKey(() => User)
userId: number;
}
I tried to specify schema inside column, but it still references tenant schema
#Table({ paranoid: true, freezeTableName: true })
export default class UserRole extends Model {
#AutoIncrement
#PrimaryKey
#Column(DataType.BIGINT)
id: number;
#ForeignKey(() => Role)
#Column(DataType.BIGINT)
roleId: number;
#Unique
#ForeignKey(() => User)
#Column({
type: DataType.BIGINT,
references: {
model: {
tableName: 'users',
schema: 'public',
},
key: 'id',
},
})
userId: number;
}

How can I create a UUID FK column in NestJS?

I am running into an odd issue where I can't create a FK relationship between two entities.
// organization.entity.ts
#PrimaryGeneratedColumn('uuid')
id: string;
...
#OneToMany(() => User, (user) => user.organization)
users: User[];
// user.entity.ts
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({
type: 'uuid',
})
organizationId: string;
...
#ManyToOne(() => Organization, (organization) => organization.users)
organization: Organization;
In my ormconfig.json file I have these settings (among connection creds)
...
"logging": true,
"entities": [
"dist/**/*.entity{.ts,.js}"
],
"synchronize": true
...
I am using "typeorm": "^0.2.45" in my package.json file.
Key columns "organizationId" and "id" are of incompatible types: character varying and uuid.
How can I create an FK relationship between users & organizations?
So from your question I understood is you want a "organizationId" field in your users table which will be a FK.
To create OnetoMany Relation between Organization and users do as below:
// organization.entity.ts
#Entity({ name: 'organizations' })
export class Organization {
#PrimaryGeneratedColumn('uuid')
id: string;
...
#OneToMany(() => User, (user) => user.organization)
users: User[];
}
// user.entity.ts
#Entity({ name: 'users' })
export class User {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'uuid' })
organizationId: string;
...
#ManyToOne(() => Organization, (organization) => organization.users)
#JoinColumn({ name: 'organizationId' })
organization: Organization;
}

TypeORM - Query OneToMany related entities with TypeORM Repository

I just trying to query a OneToMany related entities but, in this query, i need to get eager loaded data from Entity2 with query in Entity1.
Example:
I have those entities:
//Entity1
#Entity('roles')
export class Role {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
title: string;
#OneToMany(() => User, user => user.role)
users: User[];
}
//Entity2
export class User {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
name: string;
#Column('uuid')
role_id: string;
#ManyToOne(() => Role, role => role.users)
#JoinColumn({ name: 'role_id' })
role: Role;
}
So, im trying to make a query like this:
const rolesRepository = getRepository(Role);
rolesRepository.find({
where: {
// user's name
name: ILike("%john%")
},
relations: ['users']
});
I need to use user's name to find all roles who have users with name containing "John" and get role and user data (eager load) like:
Role: {
id: '6fa6fa8b-f0e1-48bf-b0ec-61eb35585eba',
title: 'Pathfinder',
users: [
{
id: 'c9097d7d-b83b-412b-9c81-6a918c07e360',
name: 'John Doe',
role_id: '6fa6fa8b-f0e1-48bf-b0ec-61eb35585eba'
},
{
id: 'ed1fffb0-dae5-46ce-83ce-38b379483c7f',
name: 'Johnny',
role_id: '6fa6fa8b-f0e1-48bf-b0ec-61eb35585eba'
}
]
}
I dont want to use { eager: true } in the entity because i just need one single query using eager loading (using in the entity i will have over-fetching).
This isn't working and i know it doesn't make sense to do a query that way. I just did it to understand the purpose.
Database: Postgres

Typeorm update record in OneToMany relation

I have the following two entities with a OneToMany/ManyToOne relation between them:
#Entity({ name: 'user' })
export class User {
#PrimaryGeneratedColumn('increment')
id: number;
#Column({ type: 'varchar' })
firstName: string;
#Column({ type: 'varchar' })
lastName: string;
#ManyToOne(() => Group, group => group.id)
#JoinColumn({ name: 'groupId' })
group: Group;
#Column({ type: 'integer' })
groupId: number;
}
#Entity({ name: 'group' })
export class Group {
#PrimaryGeneratedColumn('increment')
id: number;
#Column({ type: 'varchar' })
name: string;
#OneToMany(() => User, user => user.group)
members: User[];
}
When I create a new group in my Group repository, I can add existing members as follows:
const group = new Group();
group.name = 'Test';
group.members = [{ id: 1 }, { id: 2 }]; // user ids
this.save(group);
I am wondering if I can update existing members in a similar way. For example if a group with id 1 has two members:
{ id: 1, firstName: 'Member', lastName: 'One', groupId: 1 }
{ id: 2, firstName: 'Member', lastName: 'Two', groupId: 1 }
Is it possible to update a member through the OneToMany relation in a similar way as I'm adding them ? Something like (making this up):
const group = await repository.findOne(groupId, { relations: ['members'] });
group.members = [{ id: 1, firstName: 'Updated' }]; // this would update the firstName of member with id 1 if it exists in the relation
repository.save(group);
Thanks!
There is no built in functionality in typeorm to update specific related entity from the base entity. However if you want to do this then you can add a general function which updates the base table as well as it's relations.