question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Inefficient OneToMany Relations Query

See original GitHub issue

Hard to tell which project is responsible for your ?join= query building, be it NestJSX or NestJS or TypeORM…but I noticed 2 queries are run instead of one.

Example: I setup a super basic 2 entity system. Posts and Spaces. A Space is simply a “category”. A Post can have ONE Space, so post.entity.ts is setup like so

@ManyToOne(type => Space, space => space.posts, { nullable: false })
space: Space;

While the inverse relation on space.entity.ts is setup properly like so

@OneToMany(type => Post, post => post.space)
posts: Post[];

I have my posts controller setup to JOIN spaces properly like so

@Crud({
  model: {
    type: Post,
  },
  query: {
    join: {
      space: {eager: true},
    },
    maxLimit: 25,
  },
})

Now when I run my basic GET entpoint via curl it will JOIN in the space but I believe it is doing so inefficiently.

The NestJS console output shows 2 queries like so

query1: SELECT DISTINCT `distinctAlias`.`Post_id` as "ids_Post_id" FROM (SELECT `Post`.`id` AS `Post_id`, `Post`.`slug` AS `Post_slug`, `Post`.`title` AS `Post_title`, `Post`.`body` AS `Post_body`, `Post`.`hidden` AS `Post_hidden`, `Post`.`deleted` AS `Post_deleted`, `Post`.`indexed_at` AS `Post_indexed_at`, `Post`.`created_at` AS `Post_created_at`, `Post`.`updated_at` AS `Post_updated_at`, `space`.`id` AS `space_id`, `space`.`name` AS `space_name`, `space`.`section` AS `space_section`, `space`.`slug` AS `space_slug`, `space`.`order` AS `space_order`, `Post`.`parent_id`, `Post`.`spaceId`, `Post`.`format_id`, `Post`.`created_by`, `Post`.`updated_by` FROM `posts` `Post` INNER JOIN `spaces` `space` ON `space`.`id`=`Post`.`spaceId`) `distinctAlias` ORDER BY `Post_id` ASC LIMIT 25

query2: SELECT `Post`.`id` AS `Post_id`, `Post`.`slug` AS `Post_slug`, `Post`.`title` AS `Post_title`, `Post`.`body` AS `Post_body`, `Post`.`hidden` AS `Post_hidden`, `Post`.`deleted` AS `Post_deleted`, `Post`.`indexed_at` AS `Post_indexed_at`, `Post`.`created_at` AS `Post_created_at`, `Post`.`updated_at` AS `Post_updated_at`, `space`.`id` AS `space_id`, `space`.`name` AS `space_name`, `space`.`section` AS `space_section`, `space`.`slug` AS `space_slug`, `space`.`order` AS `space_order`, `Post`.`parent_id`, `Post`.`spaceId`, `Post`.`format_id`, `Post`.`created_by`, `Post`.`updated_by` FROM `posts` `Post` INNER JOIN `spaces` `space` ON `space`.`id`=`Post`.`spaceId` WHERE `Post`.`id` IN (1, 2, 3, 4, 5, 6)

So the first query is simply trying to get a list of post IDs, which are 1, 2, 3, 4, 5, 6

Then the second query is performing an IN statement with those same IDs. There are 2 problems with that. One is the first query is inefficient because it is querying ALL COLUMNS in its select. All it needs is just Post.id is its sub select because that is all its counting.

Second is, I don’t get the point of the first query at all. Since this is a basic OneToMany simply running one single query with a JOIN and NO IN statement would do the same thing. Basically your second query is right but you don’t need the IN statement, just

SELECT
	`Post`.`id` AS `Post_id`,
	`Post`.`slug` AS `Post_slug`,
	`Post`.`title` AS `Post_title`,
	`Post`.`body` AS `Post_body`,
	`Post`.`hidden` AS `Post_hidden`,
	`Post`.`deleted` AS `Post_deleted`,
	`Post`.`indexed_at` AS `Post_indexed_at`,
	`Post`.`created_at` AS `Post_created_at`,
	`Post`.`updated_at` AS `Post_updated_at`, 
	`space`.`id` AS `space_id`,
	`space`.`name` AS `space_name`,
	`space`.`section` AS `space_section`,
	`space`.`slug` AS `space_slug`,
	`space`.`order` AS `space_order`,
	`Post`.`parent_id`,
	`Post`.`spaceId`,
	`Post`.`format_id`,
	`Post`.`created_by`,
	`Post`.`updated_by`
FROM
	`posts` `Post`
	INNER JOIN `spaces` `space` ON `space`.`id`=`Post`.`spaceId`

Maybe I am missing the point to the first query, but its just getting a list of IDs to use later in the IN statement which I can’t see the point too.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:3
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
mreschkecommented, May 4, 2020

Not sure as I have since switched away from NestJS as I feel my API’s should be in python. Why? Because my APIs always get more complicated than just a CRUD endpoint. Endpoints that build reports, query other systems (including hardware), perform complex data analysis…python has more libraries and is a bit more powerful for me. Nothing wrong with NestJS or the node ecosystem, love the project and will use it in the future when applicable.

0reactions
michaelyalicommented, May 4, 2020

@mreschke

Endpoints that build reports, query other systems (including hardware), perform complex data analysis

That not the issue with NestJs at all. Your mistake was to rely on CRUD lib which just creates several endpoints with dumb af logic because it’s called CRUD lol 😃 I’ve never used my lib when I’m building really big and complex projects because it’s really obvious that I would need something more than just CRUD endpoints.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Efficient JPA @oneToMany relationships - Stack Overflow
The issue that I have is that the application that we are writing depends on often repeated queries across 3 entities that are...
Read more >
The best way to map a @OneToMany relationship with JPA ...
While adding a OneToMany relationship is very easy with JPA and Hibernate, knowing the most efficient way to map such an association is...
Read more >
Best Practices for Many-To-One and One ... - Thorben Janssen
Best Practices for Many-To-One and One-To-Many Association Mappings · 1 Don't use unidirectional one-to-many associations · 2 Avoid the mapping of huge to-many ......
Read more >
Most efficient way to map a @OneToMany relationship with ...
Here I have covered all possible cases of One-to-Many/Many-to-One mapping. Among all , Bidirectional `@OneToMany` association is the best way to ...
Read more >
Hibernate One to Many Annotation Tutorial - Baeldung
Now, if Cart referenced Item, but Item didn't in turn reference Cart, our relationship would be unidirectional. The objects would also have a ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found