You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeORM中左连接时限制关联子实体数量?

在Nest.js+TypeORM+PostgreSQL中实现用户关联最多5张照片的查询

实体关联确认

首先确保你的User和Photo实体的一对多关系配置正确:

User 实体

import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Photo } from './photo.entity';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @OneToMany(() => Photo, photo => photo.user, { eager: false })
  photos: Photo[];
}

Photo 实体

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { User } from './user.entity';

@Entity()
export class Photo {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  url: string;

  @Column()
  createdAt: Date; // 可选,用于自定义排序

  @ManyToOne(() => User, user => user.photos)
  user: User;

  @Column()
  userId: number; // 外键字段,必须存在
}

查询实现方案

由于TypeORM默认关联查询无法直接限制关联数据条数,结合PostgreSQL特性,以下是两种可行实现方式:

方式一:子查询筛选(简单场景)

通过子查询直接筛选每个用户的前5张照片(按ID倒序),并映射到用户的photos字段:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, QueryBuilder } from 'typeorm';
import { User } from './user.entity';
import { Photo } from './photo.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  async getUsersWithMax5Photos() {
    return this.userRepository
      .createQueryBuilder('user')
      .leftJoinAndMapMany(
        'user.photos', // 要映射到的用户实体字段
        (qb: QueryBuilder<Photo>) => {
          return qb
            .select('photo.*')
            .from(Photo, 'photo')
            .where('photo.userId = user.id')
            .orderBy('photo.id', 'DESC')
            .limit(5);
        },
        'photo',
        'photo.userId = user.id'
      )
      .getMany();
  }
}

方式二:窗口函数筛选(自定义排序场景)

如果需要按特定字段(如创建时间)排序后取前5张,可使用PostgreSQL的ROW_NUMBER()窗口函数:

async getUsersWithMax5Photos() {
  return this.userRepository
    .createQueryBuilder('user')
    .leftJoinAndMapMany(
      'user.photos',
      (qb: QueryBuilder<Photo>) => {
        return qb
          .select(`
            photo.*,
            ROW_NUMBER() OVER (PARTITION BY photo.userId ORDER BY photo.createdAt DESC) AS rn
          `)
          .from(Photo, 'photo')
          .having('rn <= 5')
          .orderBy('rn');
      },
      'photo',
      'photo.userId = user.id'
    )
    .getMany();
}

注意事项

  • 必须确保Photo实体中存在userId外键字段,否则关联查询会失败。
  • 若需对用户进行分页查询,窗口函数方案不会干扰主查询的分页逻辑。
  • 子查询方案在数据量较小时性能更优,窗口函数方案适合需要复杂排序规则的场景。

内容的提问来源于stack exchange,提问作者chirag thapa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:57:46