fill relation ManyToMany nestjs typeorm - nestjs

I have a query, I'm trying to create a ManyToMany relationship between 2 tables (products and orders) the tables are created fine, but when I want to add the logic in the service to create the records I don't understand how it should be.
This is what I have written till now:
#Entity('pedido')
export class Pedido {
#PrimaryGeneratedColumn()
id: number;
#ManyToMany(() => Product)
#JoinTable({
name: 'pedidos_products',
joinColumn: {
name: 'pedido_id',
},
inverseJoinColumn: {
name: 'product_id',
},
})
product: Product[];
#Column('decimal')
quantity: number;
#Column('decimal')
price: number;
}
#Entity('product')
export class Product {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#ManyToOne(() => Category, (category) => category.product)
category: Category;
#ManyToMany(() => Pedido)
pedido: Pedido[];
}
Service:
async createPedido(body: any) {
const pedidos = body;
const pedidoInstance = new Pedido();
const productsIds = [];
pedidos.forEach(async (item: any) => {
productsIds.push(item.product_id);
pedidoInstance.price = item.price;
pedidoInstance.quantity = item.quantity;
pedidoInstance.product = productsIds;
await this.pedidoRepository.save(pedidoInstance);
});
return {
ok: true,
};
}

Related

Save child relations with parent entity TypeORM

I'm inserting multiple entries simultaneously and wanted to store the child relationships as well, but using the code below, province isn't saving into the database. In essence, I want to save the "province" and user when I save the address, and I receive the userID and provinceID in the request.
entity.ts
#Entity()
export class Address {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
address1: string;
#Column({ nullable: true })
address2?: string;
#Column()
country: string;
#ManyToOne(() => Province, (province) => province.addresses, { lazy: true })
#JoinColumn({
name: 'province_id',
})
province: Province;
#ManyToOne(() => User, (user) => user.addresses, {
nullable: false,
onDelete: 'CASCADE',
lazy: true,
})
#JoinColumn({
name: 'user_id',
})
user: User;
}
Request from frontend:
[
{
"address1": "Test 1",
"address2": "Test 1",
"country": "Estonia",
"province_id": "3", // suppose uuid
"user_id": "4" // suppose uuid
},
{
"address1": "Test 2",
"address2": "Test 2",
"country": "Estonia",
"province_id": "3", // suppose uuid
"user_id": "4" // suppose uuid
}
]
service.ts
async saveAddresses (_addresses) {
const addresses: any = _addresses.map((address) => ({
...address,
user: address.user_id,
province: address.province_id
}));
const addressesToCreate = this.addressRepository.create(addresses);
await this.addressRepository.insert(addressesToCreate);
}
As you can see how I'm saving the records but unfortunately, the province and user saving as null and I don't want to query for province again n again.
I tried like this article, and works for me
The code:
//Entity
#Entity('organization')
export class Organization {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'varchar' })
name: string;
#OneToMany(() => Users, (obj) => obj.organization)
users: Users[];
}
#Entity('users')
export class Users {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ type: 'varchar' })
name: string;
#ManyToOne(() => Organization, (obj) => obj.users, { cascade: true }) // <--- cascade: true
organization: Organization;
}
//Service
async create(dto: CreateDto[]) {
try {
const orgEntity = function (name: string) {
const org = new Organization();
org.name = name;
return org;
};
const entity: any = dto.map((obj) => ({
...obj,
organization: orgEntity(obj.organization),
}));
const entityCreated = this._repoUser.create(entity);
await this._repoUser.save(entity); // <-- save
return entityCreated;
} catch (err) {
console.log(err);
}
}
//dto
export class CreateDto {
#ApiProperty()
#IsString()
name: string;
#ApiProperty()
#IsString()
organization: string;
}
//request
[
{
"name": "user-1",
"organization":"org-1"
},
{
"name": "user-2",
"organization":"org-2"
}
]

How do I return only the required nested field in NestJs?

I'm trying to get one record from a nested table.
controller:
#Get(':id/type')
async getType(): Promise<User[]> {
return this.userService.findType();
};
service:
async findType(id: FindOptionsWhere<number>): Promise<User[]> {
return this.userRepository.find({
select: [""], //here I want to select type.type_name
where: {user_id: id}
});
}
entity:
#Entity({ name: 'user' })
export class User {
#PrimaryGeneratedColumn()
public user_id: number;
#OneToOne(() => Type)
#JoinColumn({ name: "type_id", referencedColumnName: "type_id" })
public type: Type;
#Column({ nullable: true, name: 'test_id', type: 'int' })
public test_id: number;
table user:
user_id|type_id|test_id
table type:
type_id|type_name|type_adr
How can I retrieve only type.type_name in the url /:id/type ? thanks
First you have to fix some details, like the param in your route (id). So using your ex.
I'll going to modify the order of the route by convention.
// Controller
#Get('type/:id')
async getType(#Param('id') id: string): Promise<User[]> {
return this.userService.findType();
};
// Service
async findType(id: string): Promise<User[]> {
return this.userRepository.find({
select: { type: true },
where: { user_id: id }
});
}
// And using QueryBuilder
findType(id: string) {
return this.createQueryBuilder('user')
.select(['user.type'])
.where('user.user_id = :id', { id })
.getMany(); // or .getRawMany() to get the raw type
}

Default user getting created automatically while updating rfq

When I am trying to update the RFQ it is creating a user automatically using the default value but its nowhere mentioned in the code to create a default new user checked the relations also but couldnot find anything solid
service section
async update(id: number, data: UpdateRfqDto) {
const project = await Rfq.findOne({ where: { id: id } });
if (!project) throw new NotFoundException('Project not found');
const assignee = await this.usersService.findUserById(data.assignee);
if (!assignee) throw new NotFoundException('Assignee not found');
if (data.dueDate) data.dueDate = moment.utc(data.dueDate).format();
if (data.status != 'draft' && !(data.assignee)) throw new NotAcceptableException()
// data.user=assignee
// return data.nonMember;
if (data.nonMember) {
const mem = data.nonMember
const nonmember = (mem.includes(",")) ? mem.split(",") : mem;
this.SendEmailToNonMemberVendor(nonmember, project, data.dueDate);
}
delete data.nonMember;
// return assignee;
// data.user=assignee
this.SendEmailToProjectAssignee(assignee, data.dueDate, project);
let vendorsList = [];
let listVendor = [] ;
if (data.requestVendors.length > 0) {
const vendors=data.requestVendors.map((v)=>{
return v.id;
})
// return vendors;
let vendorsListt = await Users.findBy({ id: In(vendors) });
vendorsList.push(vendorsListt)
await this.SendEmailToRequestQuoteVendor(vendorsListt, data.dueDate, data);
}
delete data.assignee;
delete data.requestVendors;
// return data;
await Rfq.update(id, data);
const newRfq = await Rfq.findOne({
where: { id: id },
relations: ['user'],
});
newRfq.user = assignee;
newRfq.vendors = vendorsList;
await newRfq.save();
return newRfq;
}
async SendEmailToRequestQuoteVendor(vendor, dueDate, project) {
let due = dueDate ? moment(dueDate, 'DD-MM-YYYY') : 'not given';
for (let i = 0; i < vendor.length; i++) {
let emailData = {
name: vendor[i].fullName,
email: vendor[i].email,
subject: VendorRequestTemplate.subject,
body: VendorRequestTemplate.body,
// params:{},
params: {
name: vendor[i].fullName,
dueDate: due,
projectName: project.projectName,
},
};
await sendemail(emailData);
}
//
return vendor;
}
async SendEmailToProjectAssignee(assignee, dueDate, project) {
let due = dueDate ? moment(dueDate, 'DD-MM-YYYY') : 'not given';
let emailData = {
name: assignee.fullName,
email: assignee.email,
subject: AssigneeTemplate.subject,
body: AssigneeTemplate.body,
// params:{},
params: {
name: assignee.fullName,
dueDate: due,
projectName: project.projectName,
},
};
await sendemail(emailData);
return assignee;
}
async SendEmailToNonMemberVendor(vendorEmail, project, dueDate) {
let due = dueDate ? moment(dueDate, 'DD-MM-YYYY') : 'not given';
for (let i = 0; i < vendorEmail.length; i++) {
// if(!inviteSave){
// throw new BadRequestException();
// }
let emailData = {
name: 'Vendor',
email: vendorEmail[i],
subject: InviteVendorTemplate.subject,
body: InviteVendorTemplate.body,
// params:{},
params: {
name: 'Vendor',
dueDate: due,
projectName: project.projectName,
},
};
await sendemail(emailData);
}
return dueDate;
}
model:
import { QuoteMilestone } from 'src/quotePricing/models/quote-milestone.entity';
import { QuotePricing } from 'src/quotePricing/models/quote-pricing.entity';
import {
BaseEntity,
BeforeInsert,
BeforeUpdate,
Column,
CreateDateColumn,
Entity,
JoinColumn,
JoinTable,
ManyToMany,
ManyToOne,
OneToMany,
OneToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { Users } from '../../users/models/users.entity';
import { InviteVendor } from './invite.entity';
#Entity()
export class Rfq extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
projectName: string;
#Column({ unique: true, default: 'JOB-1' })
jobNumber: string;
#Column()
projectType: string;
#Column({ type: 'text' })
projectDescription: string;
#Column({ type: 'text' })
projectScope: string;
#Column()
attachment: string;
#Column({ default: null })
dueDate: Date;
#Column({ default: 'draft' })
status: string; //draft/created/assigned/quote/paid/completed
#Column()
#CreateDateColumn()
createdAt: Date;
#Column()
#UpdateDateColumn()
updatedAt: Date;
#ManyToOne(() => Users, (user) => user.rfqs) //Assignee
user: Users;
#ManyToOne(() => Users, (user) => user.created_by) //CreatedBy
created_by: Users;
#OneToMany(() => QuotePricing, (QuotePricing) => QuotePricing.rfq)
quotePricings: QuotePricing[];
#OneToMany(() => InviteVendor, (invite) => invite.project)
inviteVendor: InviteVendor[];
#OneToMany(() => QuoteMilestone, (milestone) => milestone.rfq)
milestone: QuoteMilestone[];
#ManyToMany(() => Users, (requestVendors: Users) => requestVendors.id, {
cascade: true,
})
#JoinTable({
name: 'rfqs_vendors',
joinColumn: {
name: 'rfqId',
referencedColumnName: 'id',
},
inverseJoinColumn: {
name: 'userId',
referencedColumnName: 'id',
},
})
vendors: Users[];
}
I have tried in many ways but not able to find any way out please help
and any help would be highly appriciated

Cannot query across one-to-many for property

product.entity.ts
#Entity()
export class Product extends CoreEntity {
#Field(type => String)
#PrimaryColumn('varchar2', { name: 'BAR_CODE' })
barcode: string;
#Field(type => String, { nullable: true })
#Column('varchar2', { name: 'GOODS_NAME', nullable: true })
goodsName: string | null;
#Field(type => Number, { nullable: true })
#Column('number', { name: 'SALE_PRICE', nullable: true, precision: 12, scale: 0 })
salePrice: number | null;
#Field(type => [PromotionProduct])
#OneToMany(
type => PromotionProduct,
promotionProduct => promotionProduct.product,
)
promotionProducts: PromotionProduct[];
}
promotion.entity.ts
#Entity()
export class Promotion extends CoreEntity {
#Field(type => String)
#PrimaryColumn('varchar2', { name: 'PROMOTION_CODE' })
promotionCode: string;
#Field(type => String)
#Column('varchar2', { name: 'PROMOTION_NAME' })
promotionName: string;
#Field(type => String)
#Column('varchar2', { name: 'PROMOTIONSTART_DAY' })
promotionStartDay: string;
#Field(type => String)
#Column('varchar2', { name: 'PROMOTIONEND_DAY' })
promotionEndDay: string;
#Field(type => [PromotionProduct], { nullable: true })
#OneToMany(
type => PromotionProduct,
promotionProduct => promotionProduct.promotion,
)
promotionProducts: PromotionProduct[];
}
promotionProduct.entity.ts
#Entity()
export class PromotionProduct extends CoreEntity {
#Field(type => String)
#PrimaryColumn('varchar2', { name: 'PROMOTION_CODE' })
promotionCode: string;
#Field(type => String)
#PrimaryColumn('varchar2', { name: 'BAR_CODE' })
barcode: string;
#Field(type => Number, { nullable: true })
#Column('number', { name: 'DC_SALE_PRICE' })
dcSalePrice: number | null;
#Field(type => Promotion, { nullable: true })
#JoinColumn({ name: 'PROMOTION_CODE' })
#ManyToOne(
type => Promotion,
promotion => promotion.promotionProducts,
{ nullable: true, onDelete: 'SET NULL' },
)
promotion: Promotion;
#Field(type => Product)
#JoinColumn({ name: 'BAR_CODE' })
#ManyToOne(
type => Product,
product => product.promotionProducts,
)
product: Product;
}
Promotion has many PromotionProduct (1:N)
Product has many PromotionProduct (1:N)
Example,
Product A is promotion target.
Product B is not promotion target.
So Product A has promotionProduct dcSalePrice
Product B hasn't promotionProduct dcSalePrice, just product salePrice.
I want all products with promotion, regardless of whether it's for the promotion or not.
And, PromotionStartDay is LessThanEqual Today, PromotionEndDay is MoreThanEqual.
products.service.ts
const productRepository = await connection.getRepository(Product);
const results = await productRepository.find(
{
relations: ['promotionProducts', 'promotionProducts.promotion'],
where: {
promotionProducts: {
promotion: {
promotionStartDay: LessThanOrEqual(currentDate),
promotionEndDay: MoreThanOrEqual(currentDate),
}
}
}
}
);
But it occurs an error like this:
Cannot query across one-to-many for property promotionProducts
I guess it's like the promotionProducts property doesn't have promotion, but promotionProducts relationship has promotion properties.
I'm not used to typeORM yet, so if you know it, please help me.

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

Resources