Querying with a TypeORM many-to-many relationship

Entity Program:

export abstract class ProgramBase {
  @Column('varchar')
  programName: string;

  @Column('text')
  programDescription: string;

  @Column({ type: 'boolean', default: false })
  isDeleted: boolean;

  @Column({ type: 'integer', default: 1 })
  version: number;

  @Column({
    select: false,
    nullable: true,
    insert: false,
    update: false,
    type: 'varchar',
  })
  total: string;
}

@Entity()
@Unique(['programName'])
export class Program extends ProgramBase {
  @Index()
  @PrimaryGeneratedColumn()
  programId: number;

  tasks: Task[];
  @OneToOne(() => Tag, { onDelete: 'SET NULL' })
  @JoinColumn()
  tag: Tag;

  @ManyToOne(() => User, (user) => user.programs)
  @JoinColumn({ name: 'user' })
  user: User;

  @RelationId((program: Program) => program.user)
  userId: number;

  @OneToMany(() => ProgramTask, (pt) => pt.program)
  programtask: ProgramTask[];

  @OneToMany(() => Calendar, (c) => c.program)
  calendar: Calendar[];

  @OneToMany(() => ProgramSession, (ps) => ps.program)
  sessions: ProgramSession[];

  @OneToMany(() => ProgramCalendar, (pc) => pc.program)
  programCalendar: ProgramCalendar[];
}

Entity ProgramTask:

export abstract class ProgramTaskBase {
  @Column('integer')
  order: number;

  @Column({ type: 'boolean', default: false })
  isReusable: boolean;
}

@Entity()
export class ProgramTask extends ProgramTaskBase {
  @PrimaryGeneratedColumn()
  programTaskId: number;

  @ManyToOne(() => Program)
  @JoinColumn({ name: 'program' })
  program: Program;

  @ManyToOne(() => Task, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'task' })
  task: Task;

  @RelationId((pt: ProgramTask) => pt.program)
  programId: number;

  @RelationId((pt: ProgramTask) => pt.task)
  taskId: number;
}

Entity Task:

export abstract class TaskBase {
  @Column('integer')
  order: number;

  @Column('varchar')
  taskName: string;

  @Column('text')
  taskDescription: string;

  @Column('time')
  taskDuration: string;

  @Column('varchar')
  taskColor: string;

  @Column({ type: 'boolean', default: false })
  isReusable: boolean;
}

@Entity()
export class Task extends TaskBase {
  @PrimaryGeneratedColumn()
  taskId: number;

  @Column({ type: 'integer', select: false, nullable: true })
  version: number;

  @OneToMany(() => ProgramTask, (pt) => pt.task)
  programtask: ProgramTask[];

  @ManyToOne(() => User, (u) => u.tasks)
  @JoinColumn()
  user: User;

  @RelationId((task: Task) => task.user)
  userId: number;
}

I have Program, ProgramTask and Task tables in TypeOrm. Program and ProgramTask table have a one-to-many relation, also Task and ProgramTask tables have a one-to-many relation.

I need ProgramTask table to hold some additional columns. Now my wish is to get each program task without showing ProgramTask columns. For each program, I just want to see task of that program in result.

When I am using LeftJoinAndSelect method on query builder, I get the ProgramTask attributes, too. So I tried this:

const result = await programRepo
    .createQueryBuilder('program')
    .innerJoinAndSelect(
      'program.programtask',
      'program_task',
      'program.programId = program_task.program',
    )
    .innerJoinAndSelect(
      'program_task.task',
      'task',
      'task.taskId = program_Task.task',
    )
    .getMany();

In this query result only showing programs, not tasks in programs.

What should I do?

I am expecting this result:

{
    "program": {
        // some program attributes
        task: [{
                // some task attributes
               },{
               //some taks attributes
              }]
    }
}

UPDATE

I added tasks:Task[] attribute to the Program entity and tried this query:

 const result = await programRepo
        .createQueryBuilder('program')
        .innerJoin(
          'program.programtask',
          'program_task',
          'program.programId = program_task.program',
        )
        .innerJoinAndMapOne(
          'program.tasks',
          'program_task.task',
          'task',
          'task.taskId = program_task.task',
        )
        .getMany();

But it did not worked too.

Answer №1

For my specific scenario, I have created an entity with the following relationship structure:

Program Entity:

@Entity()
export class Program extends ProgramBase {
  @PrimaryGeneratedColumn()
   id: number;

  //...include your column properties here

  @OneToMany(() => ProgramTask, (pt) => pt.programtask)
  programtasks: ProgramTask[];
}

Task Entity:

@Entity()
export class Task extends TaskBase {
  @PrimaryGeneratedColumn()
  id: number;

// include the remaining columns for tasks

  @OneToMany(() => ProgramTask, (pt) => pt.programtask)
  programtask: ProgramTask[];
}

ProgramTask Entity:

@Entity()
export class ProgramTask extends ProgramTaskBase {
  @PrimaryGeneratedColumn()
  id: number;
  
  @ManyToOne(() => Program, (program) => program.programtasks)
  //@JoinColumn({ name: 'program' }) You can remove this, as it will be automatically generated based on your column name + Id (e.g., programId)
  program: Program;

  @ManyToOne(() => Task, (task) => task.programtasks, { onDelete: 'CASCADE' })
  //@JoinColumn({ name: 'task' }) same as above
  task: Task;

// include the remaining columns for ProgramTask entity
}

The query to retrieve data is as follows:

const result = await programRepo
        .createQueryBuilder('program')
        .innerJoinAndSelect('program.programtask','programtask')
        .innerJoinAndSelect(
          'programtask.task',
          'task',
        )
        .getMany();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilize React.useImperativeHandle() for declaring custom types

function App(){ const refEl:React.MutableRefObject<any> = React.useRef(null); // I am uncertain about the appropriate type here. React.useEffect(()=>{ if(refEl.current){ refEl.current.start() } }, []); return <Countdown ref={refEl} ...

Exploring the contrast between string enums and string literal types in TypeScript

If I want to restrict the content of myKey in an object like { myKey: '' } to only include either foo, bar, or baz, there are two possible approaches. // Using a String Literal Type type MyKeyType = 'foo' | 'bar' | &ap ...

Learn the process of generating a dynamic modal window in a database using Bootstrap

Hello, I am facing an issue with accessing the data of a specific row in a table from the database using a modal window. The first for loop is meant to iterate over the rows of data on the webpage, while the second loop is designed for columns. My goal i ...

Is it possible to capture and generate an AxiosPromise inside a function?

I am looking to make a change in a function that currently returns an AxiosPromise. Here is the existing code: example(){ return api.get(url); } The api.get call returns an object of type AxiosPromise<any>. I would like to modify this function so ...

The NX monorepo from @nrwl is unable to locate the .svgr configuration file within the lib directory

Recently, I started working with NX Monorepo that consists of 2 separate react applications. In order to share icons between these apps, I decided to create an icons library. I made changes to the project.json file of the icons library and added a svg com ...

GraphQL Nexus Schema fails to retrieve related fields from TypeORM Entity Association, returning null instead

Currently in the process of constructing a GraphQL API using TypeORM and Nexus Schema. I have set up various entities with relationships between them including Product, Brand, and User. The challenge I'm encountering is that when querying the Product ...

Issue with updating initial state that is null in Redux Toolkit

Encountered an issue while using Redux Toolkit with Redux Persist. Unable to update the initial state of a user if it's null. The code consistently assigns null to the store regardless of passing parameters. import { createSlice, PayloadAction } from ...

Resolving type error issues related to using refs in a React hook

I have implemented a custom hook called useFadeIn import { useRef, useEffect } from 'react'; export const useFadeIn = (delay = 0) => { const elementRef = useRef<HTMLElement>(null); useEffect(() => { if (!elementRef.current) ...

What is the best way to organize an array both alphabetically and by the length of its elements?

Imagine I am working with an array like this: ['a', 'c', 'bb', 'aaa', 'bbb', 'aa']. My goal is to sort it in the following order: aaa, aa, a, bbb, bb, c. this.array= this.array.sort((n1, n2) => ...

Utilizing Flask to insert data into a MySQL database table

Hey there, I'm running into some trouble with inserting values into my database. While I can successfully log in using the same method on the sign-up page, I've tried various options without success. Below is my Python code: from flask import F ...

Can I assign a value from the tagModel to ngx-chips in an Angular project?

HTML code: <tag-input class="martop20 tag-adder width100 heightauto" [onAdding]="onAdding" (onAdd)="addInternalDomain($event)" type="text" Ts code: addInternalDomain(tagTex ...

Error encountered during Jasmine unit testing for the ng-redux @select directive

Here is a snippet from my component.ts file: import { Component, OnInit } from '@angular/core'; import { select } from 'ng2-redux'; import { Observable } from 'rxjs/Observable'; import { PersonalDetailsComponent } from ' ...

Create a class with additional attributes to support different types of options

I define a set of options represented by strings: export type Category = 'people' | 'projects' | 'topics' | 'tools' An index is declared as follows: interface Entry { ... } type IPostEntryIndex = { [name in Cate ...

Utilizing files that do not have the extension '.ts' or '.tsx' within the 'ts_library' as dependencies

My current challenge involves importing a JSON file from TypeScript while utilizing the resolveJsonModule flag in my tsconfig. The problem lies in how I can provide this JSON file to ts_library since it seems unable to locate the file. This issue extends t ...

Issue: Only one type can be named "Upload" within Apollo, Express, and Type-Graphql

I've encountered an issue while trying to execute a simple Mutation for uploading an image. The error I keep facing is: "Error: There can be only one type named 'Upload'." Here's the snippet of my code: import { FileUploadI, GraphQLUp ...

Is casting performed by <ClassName> in typescript?

According to the Angular DI documentation, there is an example provided: let mockService = <HeroService> {getHeroes: () => expectedHeroes } So, my question is - can we consider mockService as an instance of HeroService at this point? To provide ...

Show the key and value of a JSON object in a React component

When attempting to parse a JSON data file, I encountered an error message stating: "Element implicitly has an 'any' type because expression of type 'string' can't be used to the index type." The JSON data is sourced locally from a ...

What is the best way to manage destroyed objects?

I've been working on a PIXI.js application and I'm faced with the challenge of managing resources to prevent memory leaks. To address this issue, I am utilizing the DisplayObject.destroy method. When a display object is destroyed, many of its in ...

When creating an async function, the type of return value must be the universal Promise<T> type

https://i.stack.imgur.com/MhNuX.png Can you explain why TSlint continues to show the error message "The return type of an async function or method must be the global Promise type"? I'm confused about what the issue might be. UPDATE: https://i.stac ...

Seeking assistance with TypeScript promises

Just starting out with typescript and nodejs, but I've got to tackle some issues in the typescript code. I'm looking to execute an ECS one-off task using Pulumi. I have the documentation on how to run the task from the taskDefinition, which can ...