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

TypeORM左连接查询结果扁平化:QueryBuilder实现方案咨询

NestJS + TypeORM QueryBuilder 实现查询结果扁平化

我在NestJS中使用TypeORM操作MySQL数据库,拥有post、assets_post、asset三张表。当前编写的QueryBuilder查询返回嵌套结构,但我想直接在QueryBuilder中实现结果扁平化,无需查询后手动映射。

当前查询代码

private getAllQueryProcess(
    request: PostRequestDto,
  ): SelectQueryBuilder<PostEntity> {
    const queryBuilder = this.postEntity.createQueryBuilder('p');

    queryBuilder.where('p.id is not null');

    queryBuilder.leftJoinAndMapOne(
      'p.id',
      AssetsPostEntity,
      'ap',
      'ap.post = p.id',
    );

    queryBuilder.leftJoinAndMapOne(
      'ap.asset',
      AssetEntity,
      'a',
      'a.id = ap.asset',
    );

    queryBuilder.select([
      'p.id',
      'p.title',
      'ap.asset',
      'ap.post',
      'a.url',
    ]);

    queryBuilder.groupBy('p.id');

    queryBuilder.orderBy('p.id', 'ASC');

    return queryBuilder;
  }

当前返回的嵌套结果

{
    "id": {
        "asset": {
            "url": "https://url"
        },
        "post": 3
    },
    "title": "Some title",
}

期望的扁平化结果

{
    "id": 3, // 来自post表的id
    "url": "https://url", // 来自asset表的url
    "title": "Some title",
}

解决方案

问题根源在于使用了leftJoinAndMapOne方法,它会将关联表的数据映射到主实体的属性上,从而产生嵌套结构。要实现扁平化,需要调整关联方式和字段选择逻辑:

private getAllQueryProcess(
    request: PostRequestDto,
  ): SelectQueryBuilder<PostEntity> {
    const queryBuilder = this.postEntity.createQueryBuilder('p');

    // 改用普通leftJoin,避免自动映射嵌套结构
    queryBuilder.leftJoin(AssetsPostEntity, 'ap', 'ap.post = p.id');
    queryBuilder.leftJoin(AssetEntity, 'a', 'a.id = ap.asset');

    // 直接选择需要的字段,用AS指定与期望结果一致的键名
    queryBuilder.select([
      'p.id AS id',
      'p.title AS title',
      'a.url AS url',
    ]);

    queryBuilder.where('p.id IS NOT NULL');
    queryBuilder.groupBy('p.id');
    queryBuilder.orderBy('p.id', 'ASC');

    return queryBuilder;
  }

关键说明

  1. 替换leftJoinAndMapOne为leftJoin:普通leftJoin仅建立表关联,不会修改主实体的结构,避免产生嵌套。
  2. 字段别名配置:通过AS将数据库字段直接映射为结果对象的扁平键名,确保输出结构符合预期。
  3. 获取结果的方式:调用该方法后,使用getRawMany()而非getMany()获取结果,因为getRawMany()会直接返回数据库查询的原始扁平对象,而getMany()会尝试映射到实体类,可能保留不必要的结构。示例:
    const flatPosts = await this.getAllQueryProcess(request).getRawMany();
    

内容的提问来源于stack exchange,提问作者Duy Hưng Androgyne Tenor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:23:13