How to insert an entity with OneToMany relation in NestJS? - nestjs

There is the description how to do this in typeorm official docs https://typeorm.io/#/many-to-one-one-to-many-relations. But I can't do the same in NestJS with Repository and insert method.
I have written these entities (other columns were omitted)
#Entity()
export class News {
#OneToMany(type => NewsImage, image => image.news)
public images: NewsImage[];
}
#Entity()
export class NewsImage {
#ManyToOne(type => News, news => news.images)
public news: News;
}
I have tried something like this
function first() {
const news = new News();
const image = new NewsImage();
news.images = [ image ];
return from(this.newsRepo.insert(news))
.pipe(
switchMap(() => this.imageRepo.insert(image)),
);
}
function second() {
const news = new News();
const image = new NewsImage();
image.news = news;
return from(this.imageRepo.insert(image))
.pipe(
switchMap(() => this.newsRepo.insert(news)),
)
}
It inserts news and image, but image's newsId is null.

Check cascade property
#Entity()
export class News {
#OneToMany(type => NewsImage, image => image.news, { cascade: ['insert', 'update'] })
public images: NewsImage[];
}
Then if you do something like
let news = {
images: [{
date: "",
etc: ""
}],
title: ""
}
If then you call this.repository.save(news) it will save the news and the images. And updates too. Check more docs about this on typeorm docs.

Declaring new News() creates a new entity but does not save it to the database. You first need to insert or .save() the news object and then add it to image.
async function first() {
// you can .save() it however you want, the point is it must be saved to the db
const news = await News.create({ title: 'Async rules the world' }).save()
const image = new NewsImage()
image.news = news // now news has an id from the database
// ...
}

Related

Get All Relationship Data in AdonisJS

does anyone know how to retrieve all the data including from the relationship in AdonisJS ? ,
so I want to retrieve the user data from the User Model including the relationship data in the Post Model.
get All users
public async getUsers({ response }: HttpContextContract) {
try {
const data = await User.all()
return response.status(200).send({ "result": data })
} catch(err) {
return response.status(400).json({ error: err.message })
}
}
First, you will need to define the relationships on your model.
A User has many Posts:
export default class User extends BaseModel {
...
#hasMany(() => Post) // 👈 One-to-many relationship
public posts: HasMany<typeof Post>
}
A Post belongs to a User:
export default class Posts extends BaseModel {
...
#belongsTo(() => User) // 👈 a Post belongs to a User
public user: BelongsTo<typeof User>
}
Now, in your query, you can preload the relationship.
const users = await User
.query()
.preload('posts')
First:
You can use belongsTo in User model to make relationship data with Post model
post_model() {
return this.belongsTo("App/Models/Post")
}
Second:
Call the model use query like this:
await User.query()
.with("post_model", builder => {
builder.select("id", "name", "post")
})

CannotDetermineEntityError when saving entities with TypeORM

I created a NestJS and used TypeORM for the RDBMS(I used postgres in my project).
Post is an #Entity class, PostRepository is a Repository class for Post.
I was trying to create OnModuleInit service to initialize some data.
#Injectable()
export class PostsDataInitializer implements OnModuleInit {
private data: Post[] = [
{
title: 'Generate a NestJS project',
content: 'content',
},
{
title: 'Create GrapQL APIs',
content: 'content',
},
{
title: 'Connect to Postgres via TypeORM',
content: 'content',
},
];
constructor(private readonly postRepository: PostRepository) {}
async onModuleInit(): Promise<void> {
await this.postRepository.manager.transaction(async (manager) => {
// NOTE: you must perform all database operations using the given manager instance
// it's a special instance of EntityManager working with this transaction
// and don't forget to await things here
await manager.delete(Post, {});
console.log('deleted: {} ');
this.data.forEach(async (d) => await manager.save(d as Post));
const savedPosts = await manager.find<Post>(Post);
savedPosts.forEach((p) => {
console.log('saved: {}', p);
});
});
}
}
When starting up the application, I got the following error.
CannotDetermineEntityError: Cannot save, given value must be instance of entity class, instead object literal is given. Or you must specify an entity target to method call.
But the above save was accepting an instance of Post.
I think it is pretty much what the error says. You cannot pass literal objects to .save
private data = [
{
title: 'Generate a NestJS project',
content: 'content',
},
{
title: 'Create GrapQL APIs',
content: 'content',
},
{
title: 'Connect to Postgres via TypeORM',
content: 'content',
},
].map(data => {
const post = new Post();
Object.assign(post, data);
return post;
})
the above might solve this.
You can alternatively specify the target type as per the error message like so:
await manager.save(Post, d))
From the documentation of save() I see there is such a method as:
save<Entity, T extends DeepPartial<Entity>>(targetOrEntity: EntityTarget<Entity>, entity: T, options?: SaveOptions): Promise<T & Entity>;
nest version 9.1.8

How find entities by many to many relation entity id

I have tags and articles entities that linked by many to many.
How can I find tags if I know article id?
#Entity("articles")
class ArticleEntity {
#ManyToMany(() => TagEntity, tag => tag.articles)
#JoinTable()
tags: TagEntity[];
}
#Entity("tags")
class TagEntity {
#ManyToMany(() => ArticleEntity, article => article.tags)
articles: ArticleEntity[];
}
const articleId = 1;
this.tagRepo.find({ where: { articles: { id: articleId } } }); // ??
To load articles with tags you must specify relation in FindOptions
const articleId = 1;
const article = await connection.getRepository(ArticleEntity)
.findOne(articleId, {relations: ["tags"]});
console.log(article.tags); // contains all tags related to the article.id = 1
Using QueryBuilder you can join them
const article = await connection
.getRepository(ArticleEntity)
.createQueryBuilder("articles")
.leftJoinAndSelect("articles.tags", "tags")
.where({ id: articleId })
.getMany();
console.log(article.tags);

Statement .with builder in Adonisjs to select specifict column doesn't work

I want to get data from table relation in Adonisjs. I using .with function to get data from table relation but just for some column, but it doesn't work.
My controller code like this:
const cart = await Shop.query()
.with('products',(builder)=>{
builder.select('id','product_name')
})
.select('id_shop')
.fetch()
return response.json({
status:true,
message: false,
data: cart
})
But the result of code above is only id_shop, like this:
[
{
'id_shop': '1'
'products': []
},
{
'id_shop': '2'
'products': []
}
]
edited
I added my shop's model here:
class Shop extends Model {
static get table()
{
return 'shop'
}
static get primaryKey()
{
return 'id_shop'
}
products ()
{
return this.hasMany('App/Models/Product','id_shop', 'shop_id')
}
}
And my product's model:
class Product extends Model {
static get table()
{
return 'product'
}
static get primaryKey()
{
return 'id_product'
}
}
Whats wrong with my code?
you put wrong hasMany relation in Model
hasMany relationship like this
products ()
{
return this.hasMany('App/Models/Product','shop_id', 'id_shop')
}
or change in controller where you use builder change like this
const cart = await Shop.query()
.with('products',(builder)=>{
builder.select('id_product','product_name')
})
.select('id_shop')
.fetch()
change you id to id_product
you can try this

GraphQL error Cannot perform update query

I'm working on a ToDo list application in NodeJS, Koa, and GraphQL.
I wrote an update card mutation but when I run the query to update I get the following error:
Cannot perform update query because update values are not defined. Call "qb.set(...)" method to specify updated values.
The mutation:
import { getRepository } from 'typeorm';
import { Card } from '../../entities/card';
export const updateCardMutation = {
async updateCard(_, { id, patch }): Promise<Card> {
const repository = getRepository(Card);
const card = await repository.findOne({ id });
const result = await repository.update(id, patch);
return {
...card,
...patch,
};
},
};
I would like to know what I'm doing wrong and if something more is needed it please notify me so I will edit the question accordingly
card entity:
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
#Entity('cards')
export class Card {
#PrimaryGeneratedColumn('uuid')
id: string;
#CreateDateColumn()
created_at: Date;
#UpdateDateColumn()
updated_at: Date;
#Column('text')
title: string;
#Column('text', {
nullable: true,
})
description: string;
#Column('boolean', {
default: 'false',
})
done: boolean;
}
You need to spread the update Object.
export const updateCardMutation = {
async updateCard(_, { id, patch }): Promise<Card> {
const repository = getRepository(Card);
const card = await repository.findOne({ id });
const result = await repository.update(id, {...patch}); // here
return {
...card,
...patch,
};
},
};
The issue was when I was calling the updateMutation, it was creating the patch object of anonymous type. So it just needed to be clean before going to the DB engine
I resolved my issues by adding the following code:
{ ...patch }
Inside the next script:
export const updateCardMutation = {
async updateCard(_, { id, patch }): Promise<Card> {
const repository = getRepository(Card);
const card = await repository.findOne({ id });
const result = await repository.update(id, { ...patch }); // Added here
return {
...card,
...patch,
};
},
};
In this way, I was able to update my card.
https://github.com/typeorm/typeorm/blob/master/docs/update-query-builder.md
As an error Call qb.set() , typeorm query builder are different with other orm
await getRepository().createQueryBuilder().update(Card).set(patch)
.where("id = :id", { id })
.execute();
some how patch object may stringify [object], so you can spread it like set({...patch})
I have had this error before with my update query is nestjs & graqhql
Cannot perform update query because update values are not defined
I have fixed it by using the save() function from the repository on the same id, so I have changed from this
async update(
id: number,
updateEmployeeInput: UpdateEmployeeInput,
): Promise<Employee> {
await this.employeeRepository.update(id, updateEmployeeInput);
return this.employeeRepository.findOneOrFail(id);
}
to this
async update(
id: number,
updateEmployeeInput: UpdateEmployeeInput,
): Promise<Employee> {
await this.employeeRepository.save(updateEmployeeInput)
return this.employeeRepository.findOneOrFail(id);
}

Resources