How find entities by many to many relation entity id - node.js

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

Related

Getting random records from strapi v4 entity service

In Strapi v3 the following code would return random records:
strapi.query(table).model.query(qb => {
qb.limit(count); //with limit
qb.orderByRaw("RAND()") //with rand
}).fetchAll()
How can I achieve the same in v4?
For reference here is how I solved this:
const qb = strapi.db.entityManager
.createQueryBuilder("table")
.init({ select: ["id"] })
.getKnexQuery()
.orderByRaw(randomSort())
const ids = (await qb).map(r => r.id)
const filters = { id: { $in: ids } }
return await strapi.entityService.findMany(table, { filters })

Prisma upsertmany issue Provided List<Json>, expected SimilarCreateWithoutMovieInput

using "#prisma/client": "^2.25.0"
on prisma.upsertOneMovie. Provided List<Json>, expected SimilarCreateWithoutMovieInput or SimilarCreateWithoutMovieInput or SimilarUncheckedCreateWithoutMovieInput or SimilarUncheckedCreateWithoutMovieInput:
[0] type SimilarCreateWithoutMovieInput {
[0] id: Int
[0] backdrop_path: String
[0] title: String
[0] name: String
[0] release_date: DateTime
[0] overview: String
[0] show: TVShowCreateNestedOneWithoutSimilarInput
[0] }
code
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
...
let result = await apiRequest
let similar = result.similar.results.map(similar_movie => {
return {
id: similar_movie.id,
backdrop_path: similar_movie.backdrop_path,
title: similar_movie.title,
name: similar_movie.name,
release_date: similar_movie.release_date,
overview: similar_movie.overview,
movieId: result.id
}
})
const movie = {
id: result.id,
...
similar: {
upsert: similar
}
}
const upsertMovie = await prisma.movie.upsert({
where: { id: movie.id },
update: movie,
create: movie,
})
here is the schema.prisma
model Movie {
id Int #id
...other fields and attributes...
similar Similar[]
}
model Similar {
id Int #id #default(autoincrement())
tmdb_id Int #unique
backdrop_path String
title String?
name String?
release_date String
overview String
movie Movie? #relation(fields: [movie_id], references: [id])
show TVShow? #relation(fields: [show_id], references: [id])
movie_id Int?
show_id Int?
}
Similar is supposed to be an array [] of other Movies nested in a specific Movie object, cant be itself
I do not have experience with prisma upsert on generated types and I am getting the above error. Im expecting to upsert a Movie and at the same time upsert multiple records of Similar that are related to Movie.
i have tried using connectOrCreate but it does not support creating multiple records of similar while creating one record of movie as expected
how do I achieve that?
resources
https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#nested-writes
https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#connect-or-create-a-record
Issue was that prisma createMany is not available on sqlite, and on the postgresql connector, it is.
const movie = {
...result,
similar: {
connectOrCreate: result.similar.map(s => ({
create: s,
where: { id: s.id },
}))
}
}
const upsertMovie = await prisma.movie.upsert({
where: { id: movie.id },
update: movie,
create: movie,
})

How to use json object with where clause?

What I'm trying to achieve
Find all players which is in the authenticated users team.
What is the Problem?
Unable to use the returned json within const findUsers = await User.findAll where clause and I am unsure if this is the correct way.
Database Tables
Users Table : id (PK) , etc
Teams: id (PK) , etc
TeamUsers: id , TeamID (Foreign Key) , UserID (Foreign Key) , etc
Returning Json from FindTeamUsers (Var ob) which is correct
[{"id":2,"TeamID":1,"UserID":1,"createdAt":"2019-08-09","updatedAt":"2019-08-09"},{"id":3,"TeamID":1,"UserID":3,"createdAt":"2019-08-09","updatedAt":"2019-08-09"},{"id":76,"TeamID":1,"UserID":5,"createdAt":"2019-08-22","updatedAt":"2019-08-22"}]
Below is the Route that I am currently using using Nodejs, ExpressJS
router.get('/Team', auth, async function(req, res) {
// -- Get the Users team that is currently Authenticated (req.user.id (auth) )
const findTeam = await TeamUsers.findOne({
where: {
UserID: req.user.id
}
});
//If the User has a team
if (findTeam) {
// -- Get the players Team Mates who have the matching TeamID
const findTeamUsers = await TeamUsers.findAll({
where: {
TeamID: findTeam.TeamID
}
});
//Store the object and Display in JSON FORMAT
var ob = JSON.stringify(findTeamUsers);
console.log(ob);
if (!findTeamUsers) {
console.log('error');
} else {
//find the Users Details From the Users Table Model
//findTeamUsers - Is an array of each record found from const findTeamUsers = await TeamUsers.findAll
const findUsers = await User.findAll({
where: {
id: ob.UserID
}
});
res.status(200).json(findUsers);
}
}
});
Your ob is a string so ob.UserID is undefined. findTeamUsers (FindTeamUsers result) is an array of object so findTeamUsers.UserID would be undefined too. (array findTeamUsers does not have property UserID).
You can pass an array of UserIDs to search multiple elements (if you want to find for all UserIDs in the array):
User.findAll({
where: {
id: findTeamUsers.map(o => o.UserID)
}
})

TypeORM OneToMany filter in relations not effect to result

I have two tables:
#Entity('Reviews')
class Review {
...
#OneToMany((type) => MapCategory, map => map.review)
public categories: MapCategory[];
}
And:
#Entity('MapCategories')
export class MapCategory {
...
#ManyToOne(type => Review, (review) => review.categories)
public review: Review;
}
When I try the filter on 'categories' but the result doesn't filter 'categories' following the key that I already push.
const items = await this.reviewRepository.findAndCount({
relations: ['categories'],
where: {
categories: {
id: 1
}
}
});
We need to use queryBuilder for cases like this since find doesn't allow filtering relations:
const items = await reviewRepository.createQueryBuilder("review")
.leftJoinAndSelect("review.categories", "category")
.where("category.id = :id", { id })
.getManyAndCount()
I prefer to avoid query builder when possible.
There's a workaround for filtering based on relation fields for findOne()/find() methods that I've discovered recently. The problem with filtering related table fields only exists for ObjectLiteral-style where, while string conditions work perfectly.
Assume that we have two entities – User and Role, user belongs to one role, role has many users:
#Entity()
export class User {
name: string;
#ManyToOne(() => Role, role => role.users)
role: Role;
}
#Entity()
export class Role {
#OneToMany(() => User, user => user.role)
users: User[];
}
Now we can call findOne()/find() methods of EntityManager or repository:
roleRepository.find({
join: { alias: 'roles', innerJoin: { users: 'roles.users' } },
where: qb => {
qb.where({ // Filter Role fields
a: 1,
b: 2
}).andWhere('users.name = :userName', { userName: 'John Doe' }); // Filter related field
}
});
You can omit the join part if you've marked your relation as an eager one.

How to insert an entity with OneToMany relation in 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
// ...
}

Resources