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,
};
}
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"
}
]
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
}
I currently have a nestjs service /api/permission
To create a new permission I send the following parameters for REQUEST:
{"Id":"","EsName":"rxe2x","EnName":"rxi2x","Name":"rxclv2x","Type":"64","Role":"7,8,9"}
And RESPONSE is
{"status":201,"message":"Permission has been saved successfully.","permission":{"Id":"200","EsName":"rxe2x","EnName":"rxi2x","Name":"rxclv2x","Type":"64","Role":"7,8,9"}}
I want the Role parameter to also be saved, in the PermissionRole table, each role with an entry like this:
RoleId
PermissionId
7
200
8
200
9
200
on my permission.service.ts
async createPermission(permission: CreatePermissionDto) {
const exist = await this.permissionRepository.findOne({
where: { Name: permission.Name },
});
if (exist)
throw new ConflictException(
'The permission already exists.',
HttpStatus.CONFLICT.toString(),
);
const newPermission = await this.permissionRepository.save(permission);
return Object.assign(
{},
{
status: HttpStatus.CREATED,
message: 'Permission has been saved successfully.',
permission: newPermission,
},
);
}
summary of my Permission.entity.ts
import { Role } from './Role.entity';
#Entity('Permission', { schema: 'dbo' })
export class Permission extends BaseEntity {
#PrimaryGeneratedColumn({
type: 'int',
name: 'Id',
})
Id: number;
#Column('varchar', {
nullable: false,
name: 'Name',
})
Name: string;
#Column('int', {
nullable: false,
name: 'Type',
})
Type: number;
#Column('varchar', {
nullable: false,
name: 'EnName',
})
EnName: string;
#Column('varchar', {
nullable: false,
name: 'EsName',
})
EsName: string;
#ManyToMany(
() => Role,
(Role: Role) => Role.permissions,
)
roles: Role[];
}
summary of my Role.entity.ts
import { Permission } from './Permission.entity';
import { User } from './User.entity';
#Entity('Role', { schema: 'dbo' })
export class Role extends BaseEntity {
#PrimaryGeneratedColumn({
type: 'int',
name: 'Id',
})
Id: number;
#Column('varchar', {
nullable: false,
length: 50,
name: 'Name',
})
Name: string;
#Column('varchar', {
nullable: true,
length: 100,
name: 'AccessLevel',
})
AccessLevel: string;
#Column('bigint', {
nullable: true,
name: 'VALAccount',
})
VALAccount: string;
#Column('bit', {
name: 'CanModified',
default: '1',
})
CanModified: string;
#ManyToMany(
() => Permission,
(Permission: Permission) => Permission.roles,
{
nullable: false,
eager: true,
},
)
#JoinTable({
name: 'PermissionRole',
})
permissions: Permission[];
#ManyToMany(
() => User,
(User: User) => User.roles,
)
users: User[];
#ManyToMany(
() => User,
(User: User) => User.rolesCanAssign,
)
usersCanAssign: User[];
}
You have to define many to many like this in Permission.entity.ts
#ManyToMany(() => Role , (role) => role.id)
#JoinTable({
name: 'Permission_Role',
joinColumn: {
name: 'permissionId',
referencedColumnName: 'id'
},
inverseJoinColumn: {
name: 'roleId',
referencedColumnName: 'id'
}
})
roles: Role[];
And in permission.service.ts
async createPermission(permission: CreatePermissionDto) {
const exist = await this.permissionRepository.findOne({
where: { Name: permission.Name },
});
if (exist)
throw new ConflictException(
'The permission already exists.',
HttpStatus.CONFLICT.toString(),
);
const newPermissionDao = this.permissionRepository.create(permission);
newPermissionDao.roles = permission.roles.map((role) => {roleId: role, permissionId: newPermissionDao.id} );
const newPermission = await this.permissionRepository.save(newPermissionDao);
return Object.assign(
{},
{
status: HttpStatus.CREATED,
message: 'Permission has been saved successfully.',
permission: newPermission,
},
);
}
Basically you need to create an array of object for many to many relation like below:
permission.roles = [{
roleId: 1,
permissionId: 1
},
{
roleId: 2,
permissionId: 1
}];
I am working on an application in TypeScript and this is the first time I have gotten this error.
I am unable to use set method on an instance of a model.
Here is the model:
import mongoose from 'mongoose';
import { OrderStatus } from '#karantickets/common';
import { updateIfCurrentPlugin } from 'mongoose-update-if-current';
interface OrderAttrs {
id: string;
version: number;
userId: string;
price: number;
status: OrderStatus;
};
interface OrderDoc extends mongoose.Document {
version: number;
userId: string;
price: number;
status: OrderStatus;
};
interface OrderModel extends mongoose.Model<OrderDoc> {
build(attrs: OrderAttrs): OrderDoc;
};
const orderSchema = new mongoose.Schema({
userId: { type: String, required: true },
price: { type: Number, required: true },
status: { type: String, required: true }
}, {
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
}
}
});
orderSchema.set('versionKey', 'version');
orderSchema.plugin(updateIfCurrentPlugin);
orderSchema.statics.build = (attrs: OrderAttrs) => {
return new Order({
_id: attrs.id,
version: attrs.version,
userId: attrs.userId,
price: attrs.price,
status: attrs.status
});
};
const Order = mongoose.model<OrderDoc, OrderModel>('Order', orderSchema);
export { Order };
And here is where I am using the <object.set()> method:
export class OrderCancelledListener extends Listener<OrderCancelledEvent> {
queueGroupName = queueGroupName;
subject: Subjects.OrderCancelled = Subjects.OrderCancelled;
async onMessage(data: OrderCancelledEvent['data'], msg: Message) {
const order = Order.findOne({
_id: data.id,
version: data.version - 1
});
if (!order) throw new Error('Order not found');
order.set({ // < -------------------------------- ERROR !!
status: OrderStatus.Cancelled
});
msg.ack();
}
}
Error: Property 'set' does not exist on type 'DocumentQuery<OrderDoc | null, OrderDoc, {}>'
Thanks in advance!