How to save data from a one-to-one relationship in a so-call? TYPEORM and NESTJS - node.js

I have two entities to create in the table, one for the user and the other to store the token, and when creating a user I need both to be filled in, but I don't know how to do that via the ORM of TYPEORM, how would you do a create?
UserEntity
#Entity('Users')
export class UserEntity {
#ObjectIdColumn()
_id: ObjectId;
#Column({ type: 'string', length: 24 })
name: string;
#Column({ type: 'string', length: 55 })
password: string;
#Column({ type: 'string', length: 24 })
email: string;
#Column({ type: 'number', length: 24 })
celphone: number;
#OneToOne(() => TokenEntity, (TokenEntity) => TokenEntity.user, {
cascade: true,
})
#JoinColumn()
token: TokenEntity;
#CreateDateColumn()
created_at: Date;
#UpdateDateColumn()
updated_at: Date;
}
TokenEntity
#Entity('UserTokens')
export class TokenEntity {
#ObjectIdColumn()
_id: ObjectId;
#OneToOne(() => UserEntity, (user) => user.token)
user: UserEntity;
#Column({ type: 'string', length: '100' })
accessToken: string;
#Column({ type: 'number' })
expereIn: number;
}
UPDATED ---
code repo
export class CreateUserRepo implements ICreateUserContract {
constructor(private menagerRepo: EntityManager) {}
public async create({
user,
token,
}: ICreateUserContract.Input): Promise<void> {
const createUserByToken = new TokenEntity();
createUserByToken.accessToken = token.accessToken;
createUserByToken.expereIn = token.expireIn;
const createUser = new UserEntity();
createUser.name = user.name;
createUser.password = user.password;
createUser.celphone = user.celphone;
createUser.email = user.email;
createUser.token = createUserByToken;
await this.menagerRepo.save(createUser);
}
}
----- Updated
it is saving in both as expected, but in the User document it is saving a Token column, with token info, but I don't want that, I want a connection only, not to save the information in the same document...

As far as I understand, what you want is a bi-directional relation, which is described by typeorm. You attempted that with the inverse sides (UserEntity) => UserEntity.id and (TokenEntity) => TokenEntity.id. However, you want to access UserEntity and TokenEntity respectively, not their id. Change the accessors to (TokenEntity) => TokenEntity.user and (UserEntity) => UserEntity.tokenId, as they are declared in their classes.

Related

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

Typeorm cannot create relations between tables

Have got error 'Cannot read properties of undefined (reading 'joinColumns')'
How to implement: user can have only one assigned role with permissions to resources?
I used sequilize before, in typeorm I'm newbee
user_roles table entity:
#Entity({ name: 'user_roles' })
export class UserRoleEnitity extends DateAudit implements IUserRole {
#Column('varchar')
name: string;
#Column('varchar', {
nullable: true,
})
description?: string;
#Column('boolean', {
name: 'is_active',
default: false
})
isActive?: boolean;
#OneToMany(() => RolePermissionsEnitity, permission => permission.id)
permissions: IUserRolePermission[];
}
and users entity:
#Entity({ name: 'users' })
export class UserEnitity extends DateAudit implements IUser {
#JoinColumn({ name: 'role_id' })
roleId: string;
#OneToMany(() => UserRoleEnitity, role => role.id)
role: UserRoleEnitity;
#Column('varchar', {
unique: true,
})
username: string;
#Column('varchar')
password: string;
#Column('varchar', {
nullable: true,
})
email?: string;
#Column('varchar', {
name: 'mobile_number',
nullable: true,
})
modileNumber?: string;
#Column('varchar', {
nullable: true,
})
name?: string;
#Column('varchar', {
nullable: true
})
position?: string;
#Column({
name: 'is_verified',
default: true
})
isVerified?: boolean;
#Column('timestamp', {
name: 'password_modified_at',
default: new Date()
})
passwordModifiedAt?: Date;
}
and role_permissions
#Entity({ name: 'user_role_permissions' })
export class RolePermissionsEnitity extends DateAudit implements IUserRolePermission {
#JoinColumn({ name: 'role_id' })
roleId: string;
#ManyToOne(() => UserRoleEnitity)
role: IUserRole;
#Column({
type: 'enum',
enum: Actions,
default: Actions.READ
})
action: Actions;
#JoinColumn({ name: 'resource_id' })
resourceId: string;
#ManyToOne(() => ResourceEntity, resource => resource.id)
resource: IResource;
}
When i query repository like this:
const userEntity = await this._userRepository.findOne({
where: {
username,
},
relations: ['role']
});
Your parent entity should not refer to an ID, you should have a relation to a field that defines your user entity.
like this :
UsersRoleEntity
#OneToMany(() => RolePermissionsEnitity, permission => permission.role)
permissions: IUserRolePermission[];
UsersEntity
#OneToMany(() => UserRoleEnitity, role => role.id)
role: UserRoleEnitity;
You don't need to use JoinColumn() in ManyToOne and OneToMany relations.
You can find more information here:
TypeORM Relations Documentation

TypeORM: Select where relation property equals to x

It seems that TypeORM relation select condition only allows ID. I want to do where clause where relation property equals to x.
Example:
These are the entity:
#Entity()
export class User {
#PrimaryGeneratedColumn("uuid")
id: string;
#Column({ unique: true })
username: string;
#Column()
name: string;
#Column()
password: string;
#Column()
phone: string;
#Column({ type: "nvarchar", length: "MAX", nullable: true })
thumbnail: string;
#Column({ type: "nvarchar", length: "MAX", nullable: true })
token: string | null;
#OneToMany(
(type) => ChatRoomParticipant,
(chatRoomParticipant) => chatRoomParticipant.user
)
participants: ChatRoomParticipant[];
#ManyToOne(
(type) => Application,
(application) => application.users
)
application: Application;
}
#Entity()
export class Application {
#PrimaryGeneratedColumn("uuid")
id: string;
#Column()
name: string;
#Column({type: "nvarchar", length: "MAX", nullable: true})
token: string | null;
#Column("bigint")
dateCreated: number;
#Column()
status: string;
#ManyToOne(type => Owner, owner => owner.applications)
owner: Owner;
#OneToMany(type => User, user => user.application)
users: User[];
}
I want to select the count of user which assigned in an application.
let count = await userRepo
.createQueryBuilder("user")
.where(
"user.username = :username AND user.application.token = :applicationToken"
)
.setParameters({
username: model.username,
applicationToken: model.applicationToken,
})
.getCount()
This gives me error:
Error: Cannot call methods on nvarchar.
If I change applicationToken into applicationId then it works:
let count = await userRepo
.createQueryBuilder("user")
.where("user.username = :username AND user.application = :applicationId")
.setParameters({
username: model.username,
applicationId: "afb3015e-be49-ec11-ae4d-74d83e04f9d3",
})
.getCount();
How to compare the relation using other prop than id?
const user = await createQueryBuilder("user")
.leftJoinAndSelect("user.application", "app")
.where("user.username = :username", { username: model.username })
.andWhere("app.token = :token", { token: model.applicationToken })
.getCount();
Just use leftJoinAndSelect? You can join with the application table, alias it as app, then access it as app.token = :token.
You can read more about it here

How to do INNER JOIN in typeorm (postgresql)

I have this two entities:
#Entity()
export class Member {
#PrimaryColumn({ name: 'room_id' })
roomId: number;
#PrimaryColumn()
email: string;
#Column({ name: 'is_room_owner' })
isRoomOwner: boolean;
#Column('timestamp without time zone', { name: 'joined_at', nullable: true })
joinedAt: Date | null;
#CreateDateColumn({ name: 'created_at' })
createdAt: Date;
#ManyToOne(() => Room, room => room.members)
#JoinColumn({ name: 'room_id' })
room: Room;
}
#Entity()
export class Room {
#PrimaryGeneratedColumn({ name: 'room_id' })
roomId: number;
#Column()
name!: string;
#Column()
permanent!: boolean;
#Column()
active!: boolean;
#CreateDateColumn({ name: 'created_at' })
createdAt: Date;
#UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
#OneToMany(() => Member, member => member.room, { cascade: true })
members: Member[];
}
I would like to get the rooms by the member's email and filter if they are active.
Basically in sql it would be something like this:
select "room".*, "member".* from room "room"
inner join member "member" on "member".roomId = "room".roomId
where "room".active = :active and "member".email = :email;
It should include the members.
I am getting used to typeorm so thanks a lot for any help!
The query can be constructed using query builder as follows -
async getRoomsByMember(active: boolean, email: string): Promise<any[]> {
return await getRepository(Room)
.createQueryBuilder('room')
.innerJoinAndSelect('room.member', 'member')
.where("room.active = :active", {active: active})
.andWhere("member.email = :email", { email: email })
.getMany();
}

Nestjs Crud: Filter join request to return only data of current user

Currently I got his in my Controller:
#Crud({
model: {
type: Broker
},
query: {
join: {
user: {
eager: true,
exclude: ['password']
}
}
}
})
#Controller('broker')
#UseGuards(AuthGuard('jwt'))
export class BrokerController {
constructor(public service: BrokerService) {}
}
There is a one to many relation between user and broker. I am authenticating the users by a jwt token and I need to filter the data on the id of the user. Is there any way to do this through the Crud configuration?
As responded before by #ilker:
#CrudAuth({
property: 'user',
filter: (user) => ({
userid: user.userid,
})
})
This will get the "user" from the JWT token, and you can use it to filter the entities.
#nestsjx/crud is very great library.
Regards
In my case Broker entity is plant, so in Plant controller I have the following in order to get current user related entities and to get associated automatically on creation:
#CrudAuth({
property: 'user',
filter: (user) => ({ owner: user.userId }),
persist: (user) => ({ owner: user.userId }),
})
Enabling TypeORM debug i can see that while POST works perfectly, when retrieving data seems it adds a .id to the underlying query performed by crud library:
SELECT `Plant`.`createdAt` AS `Plant_createdAt`, `Plant`.`updatedAt` AS
`Plant_updatedAt`, `Plant`.`id` AS `Plant_id`, `Plant`.`name` AS
`Plant_name`, `Plant`.`location` AS `Plant_location`, `Plant`.`power` AS
`Plant_power`, `Plant`.`ownerId` FROM `plant` `Plant` WHERE
(`Plant`.`ownerId.id` = '5605c0f6-4817-4ae1-9364-e341140b5182')
^
^
The insert query has not appended that ".id".
Why is doing that at select time??
I also add those entities definition to give more clues about my case:
Plant:
#Entity()
export class Plant extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column({
nullable: true,
default: 0,
})
power: number;
#ManyToOne((type) => User, (user) => user.plants)
owner: User;
}
User
#Entity()
export class User extends BaseEntity {
#PrimaryColumn()
id: string; //id comes from external authentication platform
#Column()
firstName: string;
#Column()
lastName: string;
#Column({ default: true })
isActive: boolean;
#OneToMany((type) => Plant, (plant) => plant.owner)
plants: Plant[];
}
You can create a middleware that would add a user id to the req.params from your session.
This is a trick, but I don't see another solution so far
#CrudAuth({
property: 'user',
filter: (user) => ({
userid: user.userid,
})
})
You have to query like that :
#CrudAuth({
property: 'user',
filter: (user: User) => {
return {
'Tep.userId': user.id,
};
},
persist: (user: User) => ({
user,
}),
})
With :
class Tep extends EntityHelper {
#PrimaryGeneratedColumn()
id: number;
#ManyToOne(() => User, (user: User) => user.teps)
#JoinTable()
public user: User;
}

Resources