Insert data in database depending by relation - postgresql

I am using typeorm, Nest Js and postgresql database.
I have the next entities:
import {Entity, Column, PrimaryGeneratedColumn, OneToMany, ManyToOne, JoinColumn, OneToOne} from 'typeorm';
import {User} from "./user.entity";
import {MetaImages} from "./meta-images.entity";
#Entity()
export class Cars {
#PrimaryGeneratedColumn({name: "carId"})
carId: number;
#OneToMany(() => CarsColors, c => c.carId, { cascade: true })
carsColors: CarsColors[];
}
/// Colors Entity
#Entity()
export class CarsColors {
#PrimaryGeneratedColumn()
id: number;
#Column({ nullable: true})
color: string;
#ManyToOne(() => Cars, cars => cars.carId)
#JoinColumn({ name: 'carId' })
carId: Cars;
}
The idea of these entities is that i should get something like this:
{
id: 1,
carColors: [
{
id: 1,
carId: 1,
color: "red",
},
{
id: 2,
carId: 1,
color: "blue",
},
...
]
}
So, each car can have multiple colors. I want, depending by carId to add a new color in CarsColors entity.
For this i do:
await getConnection()
.createQueryBuilder()
.where("carId = :carId", {
carId: 1
})
.insert()
.into(MetaImages)
.values([{
color: 'new color',
}])
.execute();
Doing this, the new color is inserted in the db, but without carId, which is null, so the:
.where("carId = :carId", { carId: 1 })
does not work. Question: How to add new color depending by carId?

If you're already using query builder because of efficiency and you know carId, you should insert object directly into CarsColors:
await getConnection()
.createQueryBuilder()
.insert()
.into(CarsColors)
.values([{
carId: 1,
color: 'new color',
}])
.execute();

Related

I want to create a self-related table in typeorm using nestjs

I need an entity to have following columns:
Category:{ division_id:int cat_id:int cat_name:varchar }
I also want to self-related a column inside it to have parent category for some categories, so I created the entity below:
`import { ApiProperty } from '#nestjs/swagger';
import { BaseEntity } from '../embeded/base.type';
import { Commodity } from './commodity.entity';
import { Division } from '../public/division.entity';
import {
Entity,
Column,
ManyToOne,
JoinColumn,
OneToMany,
PrimaryColumn,
PrimaryGeneratedColumn,
ManyToMany,
} from 'typeorm';
#Entity()
export class Category extends BaseEntity {
#ApiProperty()
#PrimaryColumn()
division_id: number;
#ManyToOne(() => Division, (division) => division.categories, {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
#JoinColumn({ name: 'division_id', referencedColumnName: 'division_id' })
division: Division;
#PrimaryGeneratedColumn()
cat_id: number;
#ApiProperty()
#Column()
cat_name: string;
#ApiProperty()
#Column()
parent_id: number;
#ManyToOne(() => Category, (category) => category.sub_category, {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
#JoinColumn([{ name: 'parent_id', referencedColumnName: 'cat_id' }])
#ApiProperty({ type: () => Category, required: false })
parent_category: Category;
#OneToMany(() => Category, (category) => category.parent_category)
sub_category: Category[];
#ManyToMany(() => Commodity, (commodity) => commodity.categories)
commodities: Commodity[];
}`
But I got this error:
there is no unique constraint matching given keys for referenced table "category"

TypeORM OneToMany and ManyToOne relations cases 500 error on GET request

After adding OneToMany and manyToOne relations in the entities and doing GET request it shows in postman 500 error.
// Car entity
#Entity({ name: 'car' })
export class Car {
#PrimaryColumn()
car_id: number;
#Column()
name: string;
#Column()
enabled: boolean;
#ManyToOne(() => Person, (person) => person.cars)
person: Person;
}
// Person entity
#Entity({ name: 'person' })
export class Person {
#PrimaryColumn()
person_id: number;
#Column()
name: string;
#Column()
enabled: boolean;
#OneToMany(() => Car, (car) => car.person)
cars: Car[];
}
// Postman
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "",
"path": "/api/v2/cars",
"method": "GET",
}
UPDATE
In try catch it shows this error
ERROR QueryFailedError: column Car.personPersonId does not exist
//Service
GET request to fetch cars by person id
async getByPersonId(
personId: string | number,
relations: string[] = [],
throwsException = false,
): Promise<Car[] | []> {
return await this._carRepository.getByPersonId(
personId,
relations,
throwsException,
);
}
// Repository
async getByPersonId(
personId: string | number,
relations: string[] = [],
throwsException = false,
enabled?: boolean,
): Promise<Car[]> {
const where: IPersonById = {
person_id: personId,
};
if (!isNil(enabled)) {
where.enabled = enabled;
}
return await this.find({
where: {
...where,
},
relations,
})
.then((entities) => {
if (!entities && throwsException) {
return Promise.reject(
new NotFoundException(
'Car is not found by provided person id.',
),
);
}
return Promise.resolve(entities ? this.transformMany(entities) : null);
})
.catch((error) => {
console.log('ERROR', error);
return Promise.reject(error);
});
}
Try this:
on the Car entity:
#ManyToOne(type => Person, person => person.cars, {eager: false})
person: Person
on the Person Entity
#OneToMany(type => Car, car => car.person, {eager: true})
cars: Car[];

Error: Cannot query across many-to-many for property on updating

I am try to update many to may relation.
export class CreateProductDto {
#ApiProperty()
#IsString()
description: string;
#ApiProperty()
#IsString()
name: string;
#ApiProperty({ isArray: true })
#IsNumber({}, { each: true })
#IsArray()
categoryIds: number[];
}
export class UpdateProductDto extends PartialType(CreateProductDto) {}
export class ProductsService {
constructor(
#InjectRepository(Product)
private productRepository: Repository<Product>,
private categoriesService: CategoriesService,
) {}
async update(id: number, updateProductDto: UpdateProductDto) {
let categories: Category[] = undefined;
if (updateProductDto.categoryIds) {
categories = await Promise.all(
updateProductDto.categoryIds.map(
async (id) => await this.categoriesService.findOneOrFail(id),
),
);
delete updateProductDto.categoryIds;
}
await this.productRepository.update(
{ id },
{ ...updateProductDto, categories },
);
return await this.findOneOrFail(id);
}
async findOneOrFail(id: number) {
const product = await this.productRepository.findOne({ id });
if (product) {
return product;
}
throw new BadRequestException(`Product is not present`);
}
}
#Entity()
export class Product extends BaseEntity {
#Column()
description: string;
#Column()
name: string;
#ManyToMany(() => Category, (object) => object.products, {
cascade: true,
eager: true,
})
#JoinTable()
categories: Category[];
}
#Entity()
export class Category extends BaseEntity {
#Column()
name: string;
#ManyToMany(() => Product, (object) => object.categories)
products: Product[];
}
Finally when i try to call ProductsService.update with this payload it
"categoryIds": [ 2 ]
i got an error like this
Error: Cannot query across many-to-many for property categories
Can some please help me to update many to many
In your Category Entity add the relation id of Product and use save method instead of update when you update your entity.
#Entity()
export class Category extends BaseEntity {
#Column()
name: string;
#ManyToMany(() => Product, (object) => object.categories)
products: Product[];
// Add this
#Column()
productId: string;
}
To solve problemes like i use.
async dummyUpdate(objetUpdateDto: ObjectUpdateDto): Promise<TypeReturn> {
const { idObjectToUpdate, colum1ToUpate, colum2ToUpate } = objetUpdateDto;
try {
const objectToUpdate = await this.repositoryOfEntity.findOne(idObjectToUpdate);
idObjectToUpdate.colum1ToUpate = colum1ToUpate;
idObjectToUpdate.colum2ToUpate = colum2ToUpate;
await this.repositoryOfEntity.save(objectToUpdate);
return objectToUpdate,
} catch(err) {
throw new ConflictException("your message" + err);
}
}

TypeORM does not make further query for nested object

I'm currently using PostgresQL with typeORM, as well as Typegraphql. With the ManyToOne (User has many orderItems) relationship, somehow I cannot query for the nested object relation. I set the logging: true and saw that there is no SELECT query for the User entity. However, I think the query should be automatically generated giving the relation I defined in the Entity according to TypeORM.
In CartItem.ts Entity
#ObjectType()
#Entity()
export class CartItem extends BaseEntity {
#PrimaryGeneratedColumn()
#Field()
id!: number;
#Column()
#Field()
userId: string;
#Field(() => User, { nullable: true })
#ManyToOne((type) => User, (user) => user.cartItems)
user: User;
In User.ts Entity
export class User extends BaseEntity {
#PrimaryGeneratedColumn("uuid")
#Field()
id!: string;
#OneToMany((type) => CartItem, (cartItem) => cartItem.user)
cartItems: CartItem[];
In cartItem.ts Resolver
#Mutation(() => CartItem)
#UseMiddleware(isAuth)
async createCartItem(
#Arg("input") input: CartItemInput,
#Ctx() { req }: MyContext
): Promise<CartItem> {
const newCart = await CartItem.create({
quantity: input.quantity,
userId: req.session.userId,
mealkitId: input.mealkitId,
}).save();
return newCart;
With the following graphql Query, user would return null even though I'm supposed to get the username of the user
query cartItems{
cartItems {
id
quantity
userId
user{
username
}
}
}
Here is the response I received
{
"data": {
"cartItems": [
{
"id": 2,
"quantity": 2,
"userId": "5619ffb2-6ce2-42cf-bd5c-042f2685a045",
"user": null
},
{
"id": 1,
"quantity": 10,
"userId": "5619ffb2-6ce2-42cf-bd5c-042f2685a045",
"user": null
}
]
}
}```
I just ran into this myself and in my query resolver I had to leftJoinAndSelect all of the sub-objects to get it to work. You aren't showing your query resolver, but something like
async cartItems(): Promise<CartItem[]> {
return await getConnection()
.createQueryBuilder(CartItem, 'cartItem')
.leftJoinAndSelect('cartItem.user', 'user', 'cartItem.userId = user.id')
.getMany()
}

How can I use the point type coordinate information of postgis in graphql using mutations?

I created a mutation to insert new data into the postgresql called location. The column coordinate must receive and store data, for example, ST_GeomFromGeoJSON ('{ "type": "Point", "coordinates": [-48.23456,20.12345]}').
However, graphql is not working, so I don't know where to modify it. I think it's because the scalar called GeoJSONPoint that I made is not working properly. Could you tell me how to create a scalar if graphql puts the data above?
GeoJSONPoint Scalar
import { GraphQLScalarType, Kind } from 'graphql';
export const GeoJSONPoint = new GraphQLScalarType({
name: 'GeoJSONPoint',
description: 'Geometry scalar type',
parseValue(value) {
return value;
},
serialize(value) {
return value;
},
parseLiteral(ast) {
if (ast.kind === Kind.OBJECT) {
console.log(ast);
return new Object(ast);
}
return null;
}
});
location.entity
import {
Column,
CreateDateColumn,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn
} from 'typeorm';
import { Location_Group } from './location_group.entity';
import { Geometry } from 'geojson';
import { Field, ID, Int, ObjectType } from '#nestjs/graphql';
import { GeoJSONPoint } from 'src/scalar/geoJSONPoint.scalar';
#ObjectType()
#Entity('location')
export class Location {
#Field(() => ID)
#PrimaryGeneratedColumn('increment')
id: number;
#Field(() => String)
#Column({ type: 'varchar' })
name: string;
#Field(() => GeoJSONPoint)
#Column({
type: 'geometry',
nullable: true,
spatialFeatureType: 'Point',
srid: 4326
})
coordinate: Geometry;
#Field(() => Int)
#Column({ type: 'int' })
order_number: number;
#Field()
#CreateDateColumn({ type: 'timestamptz' })
created_at: Date;
#Field(() => Location_Group)
#ManyToOne(
() => Location_Group,
(location_group) => location_group.location
)
#JoinColumn([{ name: 'location_group_id', referencedColumnName: 'id' }])
location_group: Location_Group;
}
resolver
#Mutation(() => Location)
async createLocation(
#Args('data') data: LocationDataInput
): Promise<Location> {
console.log(data);
return await this.locationService.setLocation(data);
}
I solved this problem. First of all, we divided the values entered by parseLiteral in scalar into
{type: '', coordinates: []}
and removed the foreign key column.