Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeORM, ManyToMany Get posts by category id (TreeEntity materialized-path)

I'm trying to get posts by category like a CMS does.

For example query post by categorie A will include all posts attached to Categorie A and also post attached to child of Categorie A.

I really don't know how to build this query, so any help would be greatly appreciated :) .

Here is my entities:

@Tree("materialized-path")
export class Category {
  @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;


    @ManyToMany((type) => Post, (post) => post.categories)
    posts: Post[];

    @Expose()
    @TreeChildren()
    children: Category[];

    @Expose()
    @TreeParent()
    parent: Category;
}
export class Post{
   @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @ManyToMany((type) => Category, (category) => category.posts)
    @JoinTable()
    categories: Category[];
}

Followings SQL Query do the job(Example with category id 1)

SELECT * FROM post WHERE id IN (
    SELECT postId FROM post_categories_category as postCat WHERE postCat.categoryId IN (
       SELECT id FROM category WHERE category.mpath LIKE "1.%" OR category.mpath LIKE "%.1.%"
    )
)

So the question is, how to convert this SQL query into a typeORM query ?

like image 547
ZecKa Avatar asked Nov 21 '25 05:11

ZecKa


1 Answers

I just wrote a quick possible solution. I tested it and it should work fine. Just respond if it doesnt

@Entity()
@Tree("materialized-path")
export class Category extends BaseEntity {
  @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @ManyToMany((type) => Post, (post) => post.categories)
    posts: Post[];

    @TreeChildren()
    children: Category[];

    @TreeParent()
    parent: Category;

    async getPosts(): Promise<Post[]> {
      const categories = await getConnection().getTreeRepository(Category).findDescendants(this); // gets all children
      categories.push(this); // adds parent

      const ids  = categories.map(cat => cat.id) // get an array of ids

      return await Post.createQueryBuilder('post')
        .distinct(true) // dont get duplicates (posts in two categories)
        .innerJoin('post.categories', 'category', 'category.id IN (:...ids)', {ids}) // get posts where category is in categories array
        .innerJoinAndSelect('post.categories', 'cat') // add all categories to selected post 
        .orderBy('post.id')
        .getMany()
    }
}

@Entity()
export class Post extends BaseEntity {
  @PrimaryGeneratedColumn()
   id: number;

   @Column()
   title: string;

   @ManyToMany((type) => Category, (category) => category.posts)
   @JoinTable()
   categories: Category[];
}


this method uses querybuilders https://github.com/typeorm/typeorm/issues/2135#issuecomment-388801132

aswell as the findDescendants function https://typeorm.io/#/tree-entities

Hope this helps :)

like image 194
SF- Avatar answered Nov 25 '25 00:11

SF-



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!