TypeORM findManyToOne queries results in excessive and redundant query execution

I am currently working with a database table design structured as follows:

Table Appointments:

id| start_time| patientId |.. and other fields |

And another table known as the Patient table:

id| name | last_name | .. along with other fields |

In my appointment entity, I have defined the following:

@OneToMany(() => AppointmentEntity, (appt) => appt.patient)
appointments: Relation<AppointmentEntity>[];

The goal is to retrieve appointment details along with the patient's first name using only one query when given an appointment id. This is how I achieved it:

 async getAppt(apptId: any) {
    return this.apptRepo.findOne({
      relations: ['patient'],
      where: { id: apptId },
      select: {
        id: true,
        start_time: true
        patient: {
          name: true,
        },
      },
    });
  }

Although this method provides me with the desired outcome, I noticed that it executes two unnecessary database queries instead of just one. The following queries are triggered each time getAppt is called:

query: SELECT DISTINCT "distinctAlias"."AppointmentEntity_id" AS "ids_AppointmentEntity_id" FROM (SELECT "AppointmentEntity"."id" AS "AppointmentEntity_id", "AppointmentEntity"."start_time" AS "AppointmentEntity_start_time", "AppointmentEntity__AppointmentEntity_patient"."name" AS "AppointmentEntity__AppointmentEntity_patient_name" FROM "appointments" "AppointmentEntity" LEFT JOIN "patients" "AppointmentEntity__AppointmentEntity_patient" ON "AppointmentEntity__AppointmentEntity_patient"."id"="AppointmentEntity"."patientId" WHERE ("AppointmentEntity"."id" = $1)) "distinctAlias" ORDER BY "AppointmentEntity_id" ASC LIMIT 1 -- PARAMETERS: ["appt_id_xxx"]
query: SELECT "AppointmentEntity"."id" AS "AppointmentEntity_id", "AppointmentEntity"."start_time" AS "AppointmentEntity_start_time", "AppointmentEntity__AppointmentEntity_patient"."name" AS "AppointmentEntity__AppointmentEntity_patient_name" FROM "appointments" "AppointmentEntity" LEFT JOIN "patients" "AppointmentEntity__AppointmentEntity_patient" ON "AppointmentEntity__AppointmentEntity_patient"."id"="AppointmentEntity"."patientId" WHERE ( ("AppointmentEntity"."id" = $1) ) AND ( "AppointmentEntity"."id" IN ($2) ) -- PARAMETERS: ["appt_id_xxx","appt_id_xxx"

What I truly intended was for the query execution to be streamlined into just one query, similar to the example below:

select b.id, b.start_time, p.name  from appointments b
inner join patients p on p.id = b."patientId" 
where b.id = 'appt_id_xxx';

I prefer not to include aliases "b" and "p", but I require a more efficient approach like the above. The inclusion of distinctAlias and the duplicate queries are perplexing. Any insights on achieving a single query (or equivalent) would be greatly appreciated. Thank you!

Answer №1

To understand aliasing in the context of TypeORM, you can refer to the example provided in the library documentation:

Explaining Aliases

In TypeORM, when we use createQueryBuilder("user"), "user" is essentially a SQL alias. Aliases are used extensively, except when dealing with selected data.

createQueryBuilder("user") is equivalent to:

createQueryBuilder().select("user").from(User, "user")

This results in the following SQL query:

SELECT ... FROM users user

Here, "users" is the table name and "user" is the alias assigned to it. This alias is then utilized to access the table as needed:

createQueryBuilder()
    .select("user")
    .from(User, "user")
    .where("user.name = :name", { name: "Timber" })

Generating the SQL query:

SELECT ... FROM users user WHERE user.name = 'Timber'

Multiple aliases can be used within a single query builder. Each select statement can have its own alias, allowing for selection from and joining of multiple tables with their respective aliases. These aliases facilitate accessing the selected data efficiently.

The createQueryBuilder function in TypeORM enables the creation of custom queries.

Based on the library's documentation, it seems that they heavily depend on the usage of left-join. They provide a supporting function called leftJoinAndSelect in conjunction with createQueryBuilder.

For a comprehensive guide, I recommend exploring the documentation on How to create and use a QueryBuilder.

Answer №2

When it comes to the concept of eager loading, it appears that configuring it in the query is currently not an option (based on this issue: https://github.com/typeorm/typeorm/issues/7142).

However, you can enable eager loading at the model level by incorporating it into the relationship definition.

@OneToMany(() => AppointmentEntity, (appt) => appt.patient, { eager: true })
appointments: Relation<AppointmentEntity>[];

Just keep in mind that this will result in always eagerly loading the data.


To explore further details, refer to this documentation: https://github.com/typeorm/typeorm/blob/master/docs/eager-and-lazy-relations.md

Answer №3

If you are using TypeORM and have the @ManyToOne() property along with the createQueryBuilder to make database requests, it is important to utilize the leftJoinAndSelect() property.

Additionally, when using any properties like findOne or findOneBy, or all find* properties, ensure to set eager: true.

For example:

@OneToMany(() => AppointmentEntity, (appt) => appt.patient, { eager: true })appointments: Relation<AppointmentEntity>[];

I trust that this information will be beneficial to you!

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

Exploring the world of Ember through engaging click events

Exploring EmberJS and in the process of transitioning an existing website to this framework, I encountered a challenge with a Bootstrap-based dropdown. While troubleshooting this issue, I found that it deepened my understanding of Ember's concepts, al ...

Creating data types from the name of the route in vue-router route[x]

I am attempting to generate route names based on the routes defined in the Vue Router. My goal is to utilize a helper function called findRouteByName() to locate a specific route. However, I encountered an issue when trying to define the parameters of the ...

Steps for downloading a file attached to a gridview

It seems like I'm overlooking something quite straightforward. I am creating binary files that I am associating with a GridView. FileDownloadGrid.DataSource = downloadList; FileDownloadGrid.DataBind(); The part of the grid that interests me ...

Perform subtraction operation between two arrays of objects in Javascript

Hey there, I could use some guidance on the best method for subtracting values between two arrays of objects. In my scenario (backend), I retrieve data on Products from mongodb, and I also fetch Trolley data from MySql. What I'm attempting to achieve ...

What's the best way to convert a Union type into a Tuple with the same number of elements

My goal is to transform the following code snippet: type UnionType = Variant1 | Variant2 into the desired format below: type ResultingType = [UnionType, UnionType] In case the union comprises 3 member types, the tuple should contain 3 elements accordin ...

What is the best way to set a value to null in JavaScript?

Seeking assistance with the "Days Of The Week Exercise" in JavaScript. I have searched MDN and made numerous attempts, but I am still unsure about what null represents and how to effectively use it. If the argument (num) is less than 1 or greater than 7, ...

Exploring the depths of time travel in Redux without the aid of developer

Has anyone successfully achieved time traveling capabilities with Redux core? It seems that this feature is limited to the devtools and not advised for production use. I had planned on implementing Redux in a multiplayer game to assist with managing clie ...

Can you explain the use of parentheses in a typescript type when defining a key?

Could someone provide an instance of an object that matches the TypeScript type below? I'm a bit confused because I've only worked with interfaces before and have only seen square brackets. type Hash = { (data: Uint8Array): Uint8Array blockLe ...

Cached images do not trigger the OnLoad event

Is there a way to monitor the load event of my images? Here's my current approach. export const Picture: FC<PictureProps> = ({ src, imgCls, picCls, lazy, alt: initialAlt, onLoad, onClick, style }) => { const alt = useMemo(() => initial ...

Using AJAX to handle 404 errors in Slim PHP

When I attempt to retrieve data using AJAX in my Slim PHP application, I am encountering a 404 (Not found) error in the console. The specific error message is as follows: http://localhost:8888/Project/mods/public/edit-mod/ajax/get-categories?gameID=1 404 ...

Constant variable class

I need to create a unique ID for each object in a class using node. For instance, I want each instance of a Person class to have an ID starting from 1, 2, and so on. In Java, this problem can be solved with the following code: public class Person { st ...

Removing data using axios in a React project

I'm currently working on a small app using the Json server package to help me keep track of movies I want to watch in my free time. I am looking to learn React and Axios, so I decided to build this app with these technologies. The concept is simple - ...

Error in content policy for CSS in Stripe Checkout

I am currently attempting to integrate Stripe Checkout into my Ionic App. I have created a Directive that injects the form into my content view, however, upon execution, the CSS fails due to a content policy violation: checkout.js:2Refused to load the s ...

How to Generate a Unique URL in Angular 7 Using Typescript

I'm struggling to display or download a .pdf file in my Angular 7 project due to issues with window.URL.createObjectURL. Here's the code snippet I've written: this.userService.getFile(report.id).subscribe( res => { console.log(res) ...

Interactive material design drop-down menu

Currently, I am working on a dynamic drop-down menu that utilizes material-ui js. However, I have encountered an issue where clicking on one menu opens all the menus simultaneously, and vice versa when trying to close them. If you would like to view the c ...

Is Jquery getting imported correctly, but AJAX is failing to work?

I am currently working on a Chrome extension that automatically logs in to the wifi network. I have implemented AJAX for the post request, but when I inspect the network activity of the popup, I do not see any POST requests being sent. Instead, it only sho ...

What causes TypeScript to flag spread arguments within callback wrappers?

My aim is to enhance a callback function in TypeScript by wrapping it with additional logic. In order to achieve this, I have an interface called Callbacks that outlines various callback signatures. The objective is to create a wrapper function that can lo ...

Is it necessary to reboot the application server after every modification when working with ExpressJS/Node?

Currently, I am focused on developing Node.JS applications and have chosen ExpressJS as my MVC framework. My main concern at the moment is whether I should restart the server (node app.js) every time I make a change to app.js. If this is necessary, is the ...

Retrieving an image from a JSON file based on its corresponding URL

I am trying to extract the URL and display it as an image: This is how it appears in JSON: https://i.sstatic.net/vpxPK.png This is my HTML code: <ul> <li *ngFor="let product of store.Products"> <p>Product Image: {{ product.Pr ...

Issues with Bootstrap Table Column Widths not Adjusting Properly

I am facing an issue with my Bootstrap 4 table where the fixed column widths specified in the header row are not being respected when the table is rendered. The Time column, for example, should only be 5% of the width but it is taking up more space than ex ...