Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip and take doesn't work with join #4742

Open
salehmontazeran opened this issue Sep 12, 2019 · 45 comments
Open

Skip and take doesn't work with join #4742

salehmontazeran opened this issue Sep 12, 2019 · 45 comments

Comments

@salehmontazeran
Copy link

salehmontazeran commented Sep 12, 2019

Issue type:

[ ] question
[x] bug report
[ ] feature request
[ ] documentation issue

Database system/driver:

[ ] cordova
[ ] mongodb
[ ] mssql
[ ] mysql / mariadb
[ ] oracle
[x] postgres
[ ] cockroachdb
[ ] sqlite
[ ] sqljs
[ ] react-native
[ ] expo

TypeORM version:

[ ] latest
[ ] @next
[x] 0.2.18 (or put your version here)

Hi

I have 7 row in my table and it's my first query.

First Query

Organization.find({
                relations,
                order: {
                    createdAt: "DESC"
                },
                skip: pagination.skip,
                take: pagination.take
            });

First test for First query

It's my query log for just one request (my resolver dosn't have any additional middleware)
with skip: 1 and take: 2

query: SELECT DISTINCT "distinctAlias"."Organization_id" as "ids_Organization_id", "distinctAlias"."Organization_createdAt" FROM (SELECT "Organization"."id" AS "Organization_id", "Organization"."createdAt" AS "Organization_createdAt", "Organization"."updatedAt" AS "Organization_updatedAt", "Organization"."name" AS "Organization_name", "Organization"."address" AS "Organization_address", "Organization"."location" AS "Organization_location", "Organization"."contact" AS "Organization_contact", "Organization"."universityId" AS "Organization_universityId", "Organization"."type" AS "Organization_type", "Organization__university"."id" AS "Organization__university_id", "Organization__university"."createdAt" AS "Organization__university_createdAt", "Organization__university"."updatedAt" AS "Organization__university_updatedAt", "Organization__university"."name" AS "Organization__university_name", "Organization__university"."address" AS "Organization__university_address", "Organization__university"."location" AS "Organization__university_location", "Organization__university"."contact" AS "Organization__university_contact", "Organization__university"."type" AS "Organization__university_type", "Organization__units"."id" AS "Organization__units_id", "Organization__units"."createdAt" AS "Organization__units_createdAt", "Organization__units"."updatedAt" AS "Organization__units_updatedAt", "Organization__units"."name" AS "Organization__units_name", "Organization__units"."address" AS "Organization__units_address", "Organization__units"."location" AS "Organization__units_location", "Organization__units"."contact" AS "Organization__units_contact", "Organization__units"."allowedWareGroupsIds" AS "Organization__units_allowedWareGroupsIds", "Organization__units"."organizationId" AS "Organization__units_organizationId", "Organization__units"."type" AS "Organization__units_type" FROM "site" "Organization" LEFT JOIN "site" "Organization__university" ON "Organization__university"."id"="Organization"."universityId"  LEFT JOIN "site" "Organization__units" ON "Organization__units"."organizationId"="Organization"."id" WHERE  "Organization"."type" IN ($1)) "distinctAlias" ORDER BY "distinctAlias"."Organization_createdAt" DESC, "Organization_id" ASC LIMIT 2 OFFSET 1 -- PARAMETERS: ["Organization"]
query: SELECT "Organization"."id" AS "Organization_id", "Organization"."createdAt" AS "Organization_createdAt", "Organization"."updatedAt" AS "Organization_updatedAt", "Organization"."name" AS "Organization_name", "Organization"."address" AS "Organization_address", "Organization"."location" AS "Organization_location", "Organization"."contact" AS "Organization_contact", "Organization"."universityId" AS "Organization_universityId", "Organization"."type" AS "Organization_type", "Organization__university"."id" AS "Organization__university_id", "Organization__university"."createdAt" AS "Organization__university_createdAt", "Organization__university"."updatedAt" AS "Organization__university_updatedAt", "Organization__university"."name" AS "Organization__university_name", "Organization__university"."address" AS "Organization__university_address", "Organization__university"."location" AS "Organization__university_location", "Organization__university"."contact" AS "Organization__university_contact", "Organization__university"."type" AS "Organization__university_type", "Organization__units"."id" AS "Organization__units_id", "Organization__units"."createdAt" AS "Organization__units_createdAt", "Organization__units"."updatedAt" AS "Organization__units_updatedAt", "Organization__units"."name" AS "Organization__units_name", "Organization__units"."address" AS "Organization__units_address", "Organization__units"."location" AS "Organization__units_location", "Organization__units"."contact" AS "Organization__units_contact", "Organization__units"."allowedWareGroupsIds" AS "Organization__units_allowedWareGroupsIds", "Organization__units"."organizationId" AS "Organization__units_organizationId", "Organization__units"."type" AS "Organization__units_type" FROM "site" "Organization" LEFT JOIN "site" "Organization__university" ON "Organization__university"."id"="Organization"."universityId"  LEFT JOIN "site" "Organization__units" ON "Organization__units"."organizationId"="Organization"."id" WHERE  "Organization"."type" IN ($1) ORDER BY "Organization"."createdAt" DESC -- PARAMETERS: ["Organization"]

but i got my whole 7 rows and it seem two query executed!!!
In above query log, in first log LIMIT and OFFSET clause exist but in the second query they don't exist.

Second test for First query

It's my second log for skip: 7 and take: 2

query: SELECT DISTINCT "distinctAlias"."Organization_id" as "ids_Organization_id", "distinctAlias"."Organization_createdAt" FROM (SELECT "Organization"."id" AS "Organization_id", "Organization"."createdAt" AS "Organization_createdAt", "Organization"."updatedAt" AS "Organization_updatedAt", "Organization"."name" AS "Organization_name", "Organization"."address" AS "Organization_address", "Organization"."location" AS "Organization_location", "Organization"."contact" AS "Organization_contact", "Organization"."universityId" AS "Organization_universityId", "Organization"."type" AS "Organization_type", "Organization__university"."id" AS "Organization__university_id", "Organization__university"."createdAt" AS "Organization__university_createdAt", "Organization__university"."updatedAt" AS "Organization__university_updatedAt", "Organization__university"."name" AS "Organization__university_name", "Organization__university"."address" AS "Organization__university_address", "Organization__university"."location" AS "Organization__university_location", "Organization__university"."contact" AS "Organization__university_contact", "Organization__university"."type" AS "Organization__university_type", "Organization__units"."id" AS "Organization__units_id", "Organization__units"."createdAt" AS "Organization__units_createdAt", "Organization__units"."updatedAt" AS "Organization__units_updatedAt", "Organization__units"."name" AS "Organization__units_name", "Organization__units"."address" AS "Organization__units_address", "Organization__units"."location" AS "Organization__units_location", "Organization__units"."contact" AS "Organization__units_contact", "Organization__units"."allowedWareGroupsIds" AS "Organization__units_allowedWareGroupsIds", "Organization__units"."organizationId" AS "Organization__units_organizationId", "Organization__units"."type" AS "Organization__units_type" FROM "site" "Organization" LEFT JOIN "site" "Organization__university" ON "Organization__university"."id"="Organization"."universityId"  LEFT JOIN "site" "Organization__units" ON "Organization__units"."organizationId"="Organization"."id" WHERE  "Organization"."type" IN ($1)) "distinctAlias" ORDER BY "distinctAlias"."Organization_createdAt" DESC, "Organization_id" ASC LIMIT 2 OFFSET 7 -- PARAMETERS: ["Organization"]

As i expected, result was empty and just one query executed (i have just 7 row in my table)
LIMIT and OFFSET clause exist in query log.

Second Query

I changed my query to just retrieve rows without any join (relations).

Organization.find({
                order: {
                    createdAt: "DESC"
                },
                skip: pagination.skip,
                take: pagination.take
            });

First test for Second query

It's my log with skip: 1 and take: 2

query: SELECT "Organization"."id" AS "Organization_id", "Organization"."createdAt" AS "Organization_createdAt", "Organization"."updatedAt" AS "Organization_updatedAt", "Organization"."name" AS "Organization_name", "Organization"."address" AS "Organization_address", "Organization"."location" AS "Organization_location", "Organization"."contact" AS "Organization_contact", "Organization"."universityId" AS "Organization_universityId", "Organization"."type" AS "Organization_type" FROM "site" "Organization" WHERE  "Organization"."type" IN ($1) ORDER BY "Organization"."createdAt" DESC LIMIT 2 OFFSET 1 -- PARAMETERS: ["Organization"]

Everything works properly and i got expected rows.

Conclusion

I can only say it's strange behavior.

@salehmontazeran
Copy link
Author

@AlexMesser @pleerock Any idea?

@swim
Copy link
Contributor

swim commented Jan 8, 2020

Could you please share what the "relations" object looks like in your first query?

@salehmontazeran
Copy link
Author

It's just an array of string like the example in find-option document.
https://github.com/typeorm/typeorm/blob/master/docs/find-options.md#basic-options

@swim
Copy link
Contributor

swim commented Jan 8, 2020

Sadly I can't replicate the described issue with relations or sub relations. Can you provide a failing test? Otherwise the .find method maps to getMany in the SelectQueryBuilder; could you try shoe horning in getRawMany. Curious if the pagination logic in executeEntitiesAndRawResults is having an affect.

@salehmontazeran
Copy link
Author

Unfortunately i can't provide anything. I don't access to the code anymore because this issue was related to my previous job.
Thank you for your attention to this matter.

@swim
Copy link
Contributor

swim commented Jan 12, 2020

No worries at all, I saw a similar issue with incorrect select aliases - although your code omitted this I was curious what a getRawMany would return.

@pleerock this can be closed?

@thomasgauvin
Copy link

I had this issue as well, take and skip are typeorm level operations that use limit and offset. However, limit and offset do not work well because they limit all rows being returned after the join, which is not the behavior intended (at least not in my case). The solution in my case was to fetch first my base objects with skip and take (or limit and offset), and then do the next query with a whereInIds based off of the ids of my base objects.

@Menci
Copy link

Menci commented Sep 28, 2020

I think I'm facing this issue too. My query is a little complex so I have no idea why this happens.

class ... {
  async queryProblemsAndCount(
    user: UserEntity,
    hasPrivilege: boolean,
    keyword: string,
    tagIds: number[],
    ownerId: number,
    nonpublic: boolean,
    skipCount: number,
    takeCount: number
  ): Promise<[problems: ProblemEntity[], count: number]> {
    const queryBuilder = this.problemRepository.createQueryBuilder("problem").select("problem.id", "id");
    let groupByAdded = false;

    if (tagIds && tagIds.length > 0) {
      queryBuilder
        .innerJoin(ProblemTagMapEntity, "map", "problem.id = map.problemId")
        .andWhere("map.problemTagId IN (:...tagIds)", { tagIds })
        .groupBy("problem.id");
      groupByAdded = true;
      if (tagIds.length > 1) queryBuilder.having("COUNT(DISTINCT map.problemTagId) = :count", { count: tagIds.length });
    }

    if (keyword) {
      queryBuilder
        .innerJoin(
          LocalizedContentEntity,
          "localizedContent",
          'localizedContent.type = :type AND problem.id = localizedContent.objectId',
          { type: LocalizedContentType.PROBLEM_TITLE }
        )
        .andWhere("localizedContent.data LIKE :like", { like: `%${escapeLike(keyword)}%` });

      if (!groupByAdded)
        queryBuilder.groupBy("problem.id");
    }

    if (!hasPrivilege && !(user && ownerId === user.id)) {
      if (user)
        queryBuilder.andWhere(
          new Brackets(brackets =>
            brackets.where("problem.isPublic = 1").orWhere("problem.ownerId = :ownerId", { ownerId: user.id })
          )
        );
      else queryBuilder.andWhere("problem.isPublic = 1");
    } else if (nonpublic) {
      queryBuilder.andWhere("problem.isPublic = 0");
    }
    if (ownerId) {
      queryBuilder.andWhere("problem.ownerId = :ownerId", { ownerId });
    }

    // QueryBuilder.getManyAndCount() has bug with GROUP BY
    const count = Number(
      (
        await this.connection
          .createQueryBuilder()
          .select("COUNT(*)", "count")
          .from(`(${queryBuilder.getQuery()})`, "temp")
          .setParameters(queryBuilder.expressionMap.parameters)
          .getRawOne()
      ).count
    );

    queryBuilder
      .orderBy("problem.displayId IS NOT NULL", "DESC")
      .addOrderBy("problem.displayId", "ASC")
      .addOrderBy("problem.id", "ASC");
    const result = await queryBuilder.skip(skipCount).take(takeCount).getRawMany();
    return [await this.findProblemsByExistingIds(result.map(row => row.id)), count];
  }
}

The generated SQL is:

query: SELECT `problem`.`id` AS `id` FROM `problem` `problem` INNER JOIN `localized_content` `localizedContent` ON `localizedContent`.`type` = ? AND `problem`.`id` = `localizedContent`.`objectId` WHERE `localizedContent`.`data` LIKE ? GROUP BY `problem`.`id` ORDER BY `problem`.`displayId` IS NOT NULL DESC, `problem`.`displayId` ASC, `problem`.`id` ASC -- PARAMETERS: ["PROBLEM_TITLE","%a%"]

@Menci
Copy link

Menci commented Sep 28, 2020

skip and take doesn't work but limit and offset works.

@Menci
Copy link

Menci commented Oct 8, 2020

@imnotjames not only postgres, but the driver mariadb also has this bug.

@BogdanStanciu
Copy link

I have the same issue using skip and take, with a non-trivial query. The problem is that a distinct clause is added (don't know why) to the query, causing it to fail.

@mikews93
Copy link

This happens to me with both skip, take and limit, offset I'm using postgres, when I use getQuery, see what the query really looks like, with skip and take it does not write Limit and Offset to the actual SQL query but it does with limit and offset, however when I get the result from the database using getMany something happens that it does not bring the right amount of results.

@jannomeister
Copy link

I'm experiencing this issue also, using .leftJoinAndSelect and .leftJoinAndMapOne. When I use skip + take the data is not returning correctly. Same goes with offset + limit

@jannomeister
Copy link

I think I already have a solution for my problem. Might share it here. Based on this #2912 (comment), when you add the third argument which is the condition for the join it will work now as expected

@kkoomen
Copy link

kkoomen commented Feb 23, 2021

So, according to my debugging (using NestJS + MySQL) this is what I've found:

  • limit and offset should only be used when your query has no joins. As soon as you have joins, you will end up with "duplicate" rows, something like this:
| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |
| 1   | Bob        | Programming |
| 2   | Alice      | Drawing     |
| 2   | Alice      | Singing     |

If you would do .limit(2) then this would use LIMIT 2 in the query itself, thus resulting in only the first 2 records:

| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |

but actually, these are just 2 results of 2 users where hobbies is an array of hobbies and can only result in 2 result if you let TypeORM handle these. See the next point for further explanation.

  • skip and take should be used as soon as you're using and kind of join. Basically what it does is get all the results, merge them together into entities and then apply skip / take, which performance-wise a bit slower, but there's no other way to handle this. If you have no joins in your query, it is recommended to use offset and limit for faster queries.
  • Something worth mentioning as well is the issue of using .orderBy() with .skip() and .take() which is also partially related to [Question] QueryBuilder - Issues with executing a query builder. #747. When you use .offset() and .limit() you should use .orderBy('entity.created_at', 'DESC') where created_at is the raw field name. When you decide to use .orderBy() with .skip() and .take() you should use .orderBy('entity.createdAt', 'DESC') where createdAt refers to the entity field name like so:
@Entity('posts')
export class Post {
  @PrimaryGeneratedColumn({ unsigned: true })
  id: number;

  @CreateDateColumn({ name: 'created_at' }) // <--- use `.orderBy('entity.creatd_at', 'DESC')` with `.offset()` and `.limit()`
  createdAt: Date; // <--- use `.orderBy('entity.creatdAt', 'DESC')` with `.skip()` and `.take()`
}

NOTE: The above examples I mentioned are always assumed to use getMany() or getOne(). Try to avoid getRawMany() with big and advanced queries.

@yossely
Copy link

yossely commented Mar 17, 2021

I have a query with joins and I'm using skip and take but they're not being applied to entities so my result ends up with fewer entities than expected because of the duplicates that @kkoomen just explained (I could verify that by comparing the SQL query result and the entities returned with getMany()). Even though the SQL query doesn't contain any LIMIT. I'm also using .orderBy() with entity and fieldname.

@madipta
Copy link

madipta commented May 12, 2021

I have a query with joins and I'm using skip and take but they're not being applied to entities so my result ends up with fewer entities than expected because of the duplicates that @kkoomen just explained (I could verify that by comparing the SQL query result and the entities returned with getMany()). Even though the SQL query doesn't contain any LIMIT. I'm also using .orderBy() with entity and fieldname.

i have same problem too,, if i remove the join skip and take working just fine

@madipta
Copy link

madipta commented May 12, 2021

I have a query with joins and I'm using skip and take but they're not being applied to entities so my result ends up with fewer entities than expected because of the duplicates that @kkoomen just explained (I could verify that by comparing the SQL query result and the entities returned with getMany()). Even though the SQL query doesn't contain any LIMIT. I'm also using .orderBy() with entity and fieldname.

i have same problem too,, if i remove the join skip and take working just fine

ups.. it work using limit and offset

@alexweltman
Copy link

So, according to my debugging (using NestJS + MySQL) this is what I've found:

  • limit and offset should only be used when your query has no joins. As soon as you have joins, you will end up with "duplicate" rows, something like this:
| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |
| 1   | Bob        | Programming |
| 2   | Alice      | Drawing     |
| 2   | Alice      | Singing     |

If you would do .limit(2) then this would use LIMIT 2 in the query itself, thus resulting in only the first 2 records:

| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |

but actually, these are just 2 results of 2 users where hobbies is an array of hobbies and can only result in 2 result if you let TypeORM handle these. See the next point for further explanation.

  • skip and take should be used as soon as you're using and kind of join. Basically what it does is get all the results, merge them together into entities and then apply skip / take, which performance-wise a bit slower, but there's no other way to handle this. If you have no joins in your query, it is recommended to use offset and limit for faster queries.
  • Something worth mentioning as well is the issue of using .orderBy() with .skip() and .take() which is also partially related to [Question] QueryBuilder - Issues with executing a query builder. #747. When you use .offset() and .limit() you should use .orderBy('entity.created_at', 'DESC') where created_at is the raw field name. When you decide to use .orderBy() with .skip() and .take() you should use .orderBy('entity.createdAt', 'DESC') where createdAt refers to the entity field name like so:
@Entity('posts')
export class Post {
  @PrimaryGeneratedColumn({ unsigned: true })
  id: number;

  @CreateDateColumn({ name: 'created_at' }) // <--- use `.orderBy('entity.creatd_at', 'DESC')` with `.offset()` and `.limit()`
  createdAt: Date; // <--- use `.orderBy('entity.creatdAt', 'DESC')` with `.skip()` and `.take()`
}

NOTE: The above examples I mentioned are always assumed to use getMany() or getOne(). Try to avoid getRawMany() with big and advanced queries.

Yep that fixed it for me. Very interesting.

@vthanghq1
Copy link

So, according to my debugging (using NestJS + MySQL) this is what I've found:

  • limit and offset should only be used when your query has no joins. As soon as you have joins, you will end up with "duplicate" rows, something like this:
| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |
| 1   | Bob        | Programming |
| 2   | Alice      | Drawing     |
| 2   | Alice      | Singing     |

If you would do .limit(2) then this would use LIMIT 2 in the query itself, thus resulting in only the first 2 records:

| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |

but actually, these are just 2 results of 2 users where hobbies is an array of hobbies and can only result in 2 result if you let TypeORM handle these. See the next point for further explanation.

  • skip and take should be used as soon as you're using and kind of join. Basically what it does is get all the results, merge them together into entities and then apply skip / take, which performance-wise a bit slower, but there's no other way to handle this. If you have no joins in your query, it is recommended to use offset and limit for faster queries.
  • Something worth mentioning as well is the issue of using .orderBy() with .skip() and .take() which is also partially related to [Question] QueryBuilder - Issues with executing a query builder. #747. When you use .offset() and .limit() you should use .orderBy('entity.created_at', 'DESC') where created_at is the raw field name. When you decide to use .orderBy() with .skip() and .take() you should use .orderBy('entity.createdAt', 'DESC') where createdAt refers to the entity field name like so:
@Entity('posts')
export class Post {
  @PrimaryGeneratedColumn({ unsigned: true })
  id: number;

  @CreateDateColumn({ name: 'created_at' }) // <--- use `.orderBy('entity.creatd_at', 'DESC')` with `.offset()` and `.limit()`
  createdAt: Date; // <--- use `.orderBy('entity.creatdAt', 'DESC')` with `.skip()` and `.take()`
}

NOTE: The above examples I mentioned are always assumed to use getMany() or getOne(). Try to avoid getRawMany() with big and advanced queries.

Yep that fixed it for me. Very interesting.

thanks. it works like a charm.

@benjamin658
Copy link

So, according to my debugging (using NestJS + MySQL) this is what I've found:

  • limit and offset should only be used when your query has no joins. As soon as you have joins, you will end up with "duplicate" rows, something like this:
| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |
| 1   | Bob        | Programming |
| 2   | Alice      | Drawing     |
| 2   | Alice      | Singing     |

If you would do .limit(2) then this would use LIMIT 2 in the query itself, thus resulting in only the first 2 records:

| id  | first_name | hobbies     |
| --- | ---        | ---         |
| 1   | Bob        | Sports      |
| 1   | Bob        | Drawing     |

but actually, these are just 2 results of 2 users where hobbies is an array of hobbies and can only result in 2 result if you let TypeORM handle these. See the next point for further explanation.

  • skip and take should be used as soon as you're using and kind of join. Basically what it does is get all the results, merge them together into entities and then apply skip / take, which performance-wise a bit slower, but there's no other way to handle this. If you have no joins in your query, it is recommended to use offset and limit for faster queries.
  • Something worth mentioning as well is the issue of using .orderBy() with .skip() and .take() which is also partially related to [Question] QueryBuilder - Issues with executing a query builder. #747. When you use .offset() and .limit() you should use .orderBy('entity.created_at', 'DESC') where created_at is the raw field name. When you decide to use .orderBy() with .skip() and .take() you should use .orderBy('entity.createdAt', 'DESC') where createdAt refers to the entity field name like so:
@Entity('posts')
export class Post {
  @PrimaryGeneratedColumn({ unsigned: true })
  id: number;

  @CreateDateColumn({ name: 'created_at' }) // <--- use `.orderBy('entity.creatd_at', 'DESC')` with `.offset()` and `.limit()`
  createdAt: Date; // <--- use `.orderBy('entity.creatdAt', 'DESC')` with `.skip()` and `.take()`
}

NOTE: The above examples I mentioned are always assumed to use getMany() or getOne(). Try to avoid getRawMany() with big and advanced queries.

What if I want to order by joined table's column? I use the take and addOrderBy, the behavior is really confusing.

@MoSattler
Copy link

MoSattler commented Feb 10, 2022

Something worth mentioning as well is the issue of using .orderBy() with .skip() and .take() which is also partially related to #747

Is there any way around this? Right now skip and take give me wrong values, and I guess it's because of an orderBy.

const query = Session.createQueryBuilder("session")
      .leftJoinAndSelect("session.reviews", "reviews")
      .orderBy({
        "session.date": "DESC",
        "reviews.created": "ASC",
      });
      
 console.log(await query.getMany())
 console.log(await query.skip(1).take(1).getMany())

This interestingly returns the entries in correct order, but the skip seems to be ignored:

    [
      Session {
        id: 'b1e5bf67-0e91-4569-9d73-a8a4286cee16',
      },
      Session {
        id: '3c5255d4-a7a9-4f8c-a2b2-fe77f6b3174f',
      }
    ] 
    [
      Session {
        id: 'b1e5bf67-0e91-4569-9d73-a8a4286cee16',
      }
    ]

as you can see, the skip query returns the first item, not the second.

@netojose
Copy link

2022 and I having the same issue on postgres. I solved replacing skip() and take() by limit() and offset()

@to-long
Copy link

to-long commented Jun 7, 2022

Awaiting for 6 month and it still haven't fixed yet. I will give a try on Prisma

Fanta335 added a commit to Fanta335/dev-meetup-backend that referenced this issue Aug 14, 2022
When the query has `join`, `take()/skip()` should be used. ref: typeorm/typeorm#4742 (comment)
@veeresh-dg
Copy link

Facing same issue for mysql also, it's working for limit and offfset.

@LuckyArdhika
Copy link

Facing same issue for mysql also, it's working for limit and offfset.

Same with postgres, works using limit and offset.

@yearsalary
Copy link

Same with mariadb, works using limit.
It should be fixed!

@pablo-padua
Copy link

pablo-padua commented Dec 30, 2022

I ran into the same issue with mssql, I had a pagination middleware that used the .find() method and skip and take worked fine, however I was forced to use the .createQueryBuilder() and getRawMany() methods when I needed some specific fields that were part of the entity's relationship, therefore using leftJoin() along the way... Using .offset() instead of skip and .limit() instead of take worked out great for me. Thanks for the suggestion @Menci

@chemic
Copy link

chemic commented Feb 2, 2023

3 years and still not fixed? I though TypeORM was a serious ORM :(

@LuckyArdhika
Copy link

3 years and still not fixed? I though TypeORM was a serious ORM :(

This is just Open Source ORM, maybe the owner have no time, and its depend on the community too btw.

@cdbattags
Copy link

Any new updates here? We're facing the same today.

@hastalavistababy
Copy link

Any new updates here? We're facing the same today.

Same, As I know not fixed yet

@dimartiro
Copy link

4 years and still not fixed? really? I cannot use skip and take to paginate through 100k records. Common

@dev1pavlo
Copy link

Instead of writing skip/take (that creates outer subquery with DISTINCT)

const [users, count] = await query
      .skip(10)
      .take(10)
      .orderBy('createdAt', 'ASC')
      .getManyAndCount();

I managed to do it like this:

const [users, count] = await query
      .distinct()
      .offset(10)
      .limit(10)
      .orderBy('createdAt', 'ASC')
      .getManyAndCount();

So basically I gave limit/offset an opportunity to fetch dublicates, but erased them using distinct.
To increase performance you can try using distinctOn

@netojose
Copy link

netojose commented Aug 4, 2023

Me too, since 2022 replacing skip() and take() by limit() and offset()

@dimartiro
Copy link

I've been trying the use of skip & take and they end up translated to limit and offset in SQL for find like queries (not using query builder)

@falyoun
Copy link

falyoun commented Aug 24, 2023

Same here, any update on this?

@Arsenalist
Copy link

Neither of these work if you try to sort by a joined column.

@dimartiro
Copy link

Based on my experience this is solved in postgres, I'm using multiple complex find queries with skip and take and they are correctly translated into limit and offset as I expected.

Can you bring more examples with all the related entities or an example repo to reproduce?

@royalrover
Copy link

not work in mysql, 4 years later....

@santimakci
Copy link

Same problem here. When I add take and limit I have this error:

Unknown column 'distinctAlias.car_updatedAt' in 'field list'

WIthout pagination, It works fine.

@lolicrafter
Copy link

ohh, now 2023, near 2024. still a problem. i spent 2 hours to resolve this problem. finally,use limit()&offset(), not take()&skip()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests