I have two tables: user and pet
My goal is to GET all active users active pets (active means enabled is true).
When I try to join those two tables to be able to filter active users I am getting 500 error.
I have used getRawMany and getMany, does not help.
#Entity({ name: 'pet' })
export class Pet {
#PrimaryColumn()
id: number;
#Column()
user_id: number;
#Column()
name: string;
#Column()
enabled: boolean;
#ManyToOne(() => User, (user) => user.pets)
user: User;
}
#Entity({ name: 'user' })
export class User {
#PrimaryColumn()
user_id: number;
#Column()
name: string;
#Column()
enabled: boolean;
#OneToMany(() => Pet, (pet) => pet.user)
pets: Pet[];
}
// Service
async getActiveUsersActivePets(
pageOptionsDto: PageOptionsDto,
relations: string[] = [],
throwsException = false,
): Promise<PageDto<Pet>> {
const queryBuilder = this._petsRepository
.createQueryBuilder('pet');
queryBuilder
.leftJoinAndSelect('pet.user', 'user')
.where('enabled = :enabled', { enabled: true })
.skip(pageOptionsDto.skip)
.take(pageOptionsDto.take);
const itemCount = await queryBuilder.getCount();
const entities = await queryBuilder.getRawMany();
const pageMetaDto = new PageMetaDto({ itemCount, pageOptionsDto });
return new PageDto(entities, pageMetaDto);
}
// Error
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "",
"path": "/api/v2/pets",
"method": "GET",
"timeStamp": "2022-04-28T13:53:18.863Z"
}
Related
I have a few entities created on TypeORM and I want to upsert an array of data with all the entities. Here I have the entities:
#Entity({name: "__sales_rep"})
export class SalesRep {
#PrimaryColumn()
ldap: string;
#Column("text")
name: string
#OneToMany(() => ParentCompany, (parent_company) => parent_company.sales_rep, { cascade: ['insert', 'update'] })
parent_companies: ParentCompany[]
}
#Entity({name: "__parent_company"})
export class ParentCompany {
#PrimaryColumn()
id: number;
#Column("text")
name: string
#OneToMany(() => Advertiser, (advertiser) => advertiser.parent_company, { cascade: ['insert', 'update'] })
advertisers: Advertiser[]
#ManyToOne(() => SalesRep, (sales_rep) => sales_rep.parent_companies)
sales_rep: SalesRep
}
#Entity({name: "advertiser"})
export class Advertiser {
#PrimaryColumn()
id: number;
#Column("text")
name: string
#ManyToOne(() => ParentCompany, (parent_company) => parent_company.advertisers)
parent_company: ParentCompany
}
And here is how I am trying to insert the data as cascading the data. I believe the problem is that when I insert two advertisers with the same parent_company for example the constraints of the foreign key aren't allowing me to make the entire insertion.
async function loadData(data) {
console.log("Beggning data insertion");
try{
const insertData = data.rows.map((row) => {
const currentSalesRep ? {
ldap: row.ldap,
name: row.full_name
},
currentParentCompany = {
id: row.parent_company_id,
name: row.parent_company_name,
sales_rep: currentSalesRep
};
return {
id: row.advertiser_id,
name: row.advertiser_name,
parent_company: currentParentCompany
}
})
salesRepRepository
.upsert(insertData, ['id']);
typeorm
}
catch(e){
logger.error(e)
throw e;
}
}
I want to add query parameter to my queryBuilder but it returns error invalid input syntax for type json. What is the correct way to send this parameter?
My query:
const foundedUserContacts = await this.userBookContactRepository
.createQueryBuilder('userBookContacts')
.select(['userBookContacts.contacts'])
.andWhere(`contacts #> '[{ "phoneNumber": :phoneNumber }]'`, {
phoneNumber: user.phoneNumber,
})
.getMany();
This works ok:
const foundedUserContacts = await this.userBookContactRepository
.createQueryBuilder('userBookContacts')
.select(['userBookContacts.contacts'])
.andWhere(`contacts #> '[{ "phoneNumber": "${user.phoneNumber}" }]'`)
.getMany();
My schema is:
#Entity({ name: 'userBookContacts' })
#Unique('userUuid_userPhone', ['userUuid', 'phoneNumber'])
export class UserBookContact {
#PrimaryGeneratedColumn()
id: number;
#Column()
userUuid: string;
#Index()
#Column()
phoneNumber: string;
#Column({
type: 'jsonb',
nullable: true,
default: '[]',
})
contacts: UserContact[];
}
These are my tables:
#Entity('personas')
export class Personas {
#PrimaryGeneratedColumn()
#IsNumber()
id: number;
#Column({type:"varchar",length:100})
#IsNotEmpty()
nombre: string;
#OneToMany(type => Contactos, contactos => contactos.idpersona, {cascade: true})
contactos : Contactos[]
}
#Entity('contactos')
export class Contactos {
#PrimaryGeneratedColumn()
#IsNumber()
id: number;
#Column()
#IsNotEmpty()
idpersona: number;
#ManyToOne(type => Personas, {
})
#JoinColumn({name: "idpersona"})
persona: string;
#Column({type:"varchar",length:100})
nombre: string;
#Column({type:"varchar",length:11})
telefono: string;
}
This is the body of the query to add the records:
{
"nombre":"TestPersona",
"contactos":[{
"nombre":"TestContacto",
"telefono": "123456789"}
]
}
This is the error: [ExceptionsHandler] Field 'idpersona' doesn't have a default value.
It is assumed that the field idPersona in Contacts, should be inserted automatically. What am I doing wrong?. From already thank you very much.
I think you need to add cascade: ['insert'] and possibly add the inverseSide (second param) to #OneToMany:
#Entity({ name: 'persona' })
export class Persona {
#PrimaryGeneratedColumn()
public id: number
#Column()
public nombre: string
#OneToMany(() => Contacto, (contacto) => contacto.idpersona, {
cascade: ['insert']
})
public contactos: Contacto[]
}
#Entity({ name: 'contacto' })
export class Contacto {
#PrimaryGeneratedColumn({
name: 'id',
})
public id: number
#ManyToOne(() => Persona, (persona) => persona.contactos, {
nullable: false,
})
#JoinColumn({ name: 'idpersona' })
#Column()
public idpersona: string
#Column()
public telefono: string
}
Then you can do:
const persona = {
nombre: 'nombre',
contactos: [{
telefono: '123456789',
}]
}
const personaGuardada = await entityManager.getRepository('persona').save([persona])
I leave the way I fix it, in case it helps someone in the future.
In personas changed:
#OneToMany(() => Contacto, (contacto) => contacto.idpersona, {
cascade: ['insert']
})
public contactos: Contacto[]`
with:
#OneToMany(type => Contactos, contactos => contactos.personas,{
cascade : true,
})
public contactos: Contactos[];`
In contactos changed:
#Column()
#IsNotEmpty()
idpersona: number;
#ManyToOne(type => Personas, {
})
#JoinColumn({name: "idpersona"})
persona: string;`
with:
#ManyToOne(() => Personas, personas => personas.id, {nullable: false})
#JoinColumn({name: "idpersona"})
personas: Personas;
I have a Patient entity:
#Entity()
#ObjectType()
#InputType('PatientInput')
export class Patient extends BaseEntity {
#PrimaryGeneratedColumn()
#Field(type => Int, { nullable: true })
id: number
#Column({ length: 500 })
#Field({ nullable: true })
firstName?: string
#Column({ length: 500 })
#Field({ nullable: true })
lastName?: string
#Field(type => MedicalCondition, { nullable: true })
#OneToMany(type => MedicalCondition, medicalCondition => medicalCondition.patient, { cascade: true })
medicalConditions?: MedicalCondition[]
}
And a MedicalCondition entity:
#ObjectType()
#Entity()
#InputType('medicalCondition')
export class MedicalCondition extends BaseEntity {
#Field({nullable: true})
#PrimaryGeneratedColumn()
id: number
#Field(type => Int, { nullable: true })
#RelationId((medicalCondition: MedicalCondition) => medicalCondition.patient)
#Column()
patientId?: number
#Field(type => Patient, { nullable: true })
#ManyToOne(type => Patient, patient => patient.medicalConditions, {
onDelete: 'CASCADE',
})
#JoinColumn()
patient?: Patient
#Field()
#Column()
name: string
#Field({nullable: true})
#Column()
startDate?: Date
}
When trying to create an instance of patient using the BaseEntity create function, the patient is created but in the medical conditions array only containes the last element and all the rest disappear even if there were many elements.
#Mutation(returns => Patient)
async create(#Args('patient') newPatientInput: Patient, #CurrentUser() user: User, #Useragent() useragent): Promise<Patient> {
const newPatient: Patient = Patient.create(newPatientInput)
const event = createEvent({ useragent, actionType: 'add_patient', userId: user.id })
const p = await this.patientService.create(newPatient, event)
return p
}
create = async (patient: Patient, event: EventLog): Promise<Patient> => {
const isExist = await this.isPatientExist({ firstName: patient.firstName, lastName: patient.lastName, birthDate: patient.birthDate })
if (isExist > 0) {
throw new Error('Patient already exist')
} else {
const transactionResult = runTransaction(async (em) => {
const eventLog = EventLog.create(event)
await em.save(eventLog)
return await em.save(patient)
})
return transactionResult
}
}
I tried to directly save the entity without invoting create():
return await em.save(Patient, patient)
and that was the result of the saving:
medicalConditions:
[ { id: 36,
name: 'heartDisease',
startDate: 2016-07-31T21:00:00.000Z,
kin: 'father',
note: '',
patientId: 26,
createdAt: 2019-11-24T17:11:22.376Z,
updatedAt: 2019-11-24T17:11:22.376Z },
{ id: null,
name: 'previousHeartAttack',
startDate: 2018-04-30T21:00:00.000Z,
kin: 'brother',
note: '' },
{ id: null,
name: 'highBloodPressure',
startDate: 2018-03-31T21:00:00.000Z,
kin: 'sister',
note: '' } ],
Tried google for it and didn't find any known issue.
So the willing result would be to create an entity deeply, is that a possible behavior?
I have 2 following entities with Many To Many relationship
User entity (relationship owned by the User entity)
import { Entity, Column, PrimaryGeneratedColumn, UpdateDateColumn, ManyToMany, JoinTable, CreateDateColumn } from 'typeorm';
import { Role } from './role.schema';
#Entity('Users')
export class User {
#PrimaryGeneratedColumn({ name: 'Id' })
id: number;
#Column({
name: 'Email',
length: 100,
unique: true
})
email: string;
#Column({
name: 'FirstName',
length: 30
})
firstName: string;
#Column({
name: 'LastName',
length: 30
})
lastName: string;
#ManyToMany(type => Role, { eager: true })
#JoinTable({
name: 'UserRoles',
joinColumns: [
{ name: 'UserId' }
],
inverseJoinColumns: [
{ name: 'RoleId' }
]
})
roles: Role[];
}
Role entity (with two existing roles: Admin and User)
import { Entity, Column, PrimaryGeneratedColumn, ManyToMany } from 'typeorm';
import { User } from './user.schema';
#Entity("Roles")
export class Role {
#PrimaryGeneratedColumn({ name: 'Id' })
id: number;
#Column({
name: 'Name',
length: 50,
unique: true
})
name: string;
#ManyToMany(type => User, user => user.roles)
users: User[];
}
the design of application is such that Role name is sent in request in the form of an array e.g. ['Admin', 'User']
Now while inserting a User,
currently I first retrieve Role object from database based on the role name array received in request (to assign a desired role),
then assign it to the User object (roles property) and
then finally call save method on User object to insert the record in User table.
Snippet:
createConnection(connectionConfig as ConnectionOptions).then(async connect => {
let userRepo = connect.getRepository(User);
let roleRepo = connect.getRepository(Role);
let roles = ['Admin', 'User'];
let user = userRepo.create();
return roleRepo.createQueryBuilder('role').where('role.name IN (:roleNames)', { roleNames: roles }).getMany().then((roles) => {
user.email = 'test1#test.test';
user.firstName = 'TestFName';
user.lastName = 'TestLName';
user.roles = roles;
return userRepo.save(user)
})
}).catch(error => {
console.log(error);
});
This results in many database calls. It would be great if some one can enlighten me with smarter and more elegant way ( using fluent QueryBuilder to achieve above result)