iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 20
0
Modern Web

讀官網文件邊走邊學nest.js系列 第 20

Day20-TypeORM(七) Query Builder Select(下)

  • 分享至 

  • xImage
  •  

除了昨天,今天把我在官網關於Query Builder會用的功能做介紹,主要是

  • 分頁(pagination)
  • select部分欄位
  • 隱藏欄位

分頁

今天另外以role name作為query 變數加上分頁

有三個變數,建立新的queryUserDTO

export class UserQueryDTO{
    @IsString()
    name: string;
    
    @IsNumber()
    page: number;

    @IsNumber()
    pageSize: number;
}

修改app.controller query部分
```javascript
 queryByDepName(@Query() query: UserQueryDTO){
    //return this.usersService.getUsersByDepName(query);
    return this.usersService.getUsersByRoleName(query);
  }

新增getUsersByRoleName於app.service.ts

async getUsersByRoleName(query: UserQueryDTO){
          return await this.userRepo
            .createQueryBuilder('u')
            .leftJoinAndSelect('u.roles', 'r')
            .leftJoinAndSelect('u.dep', 'd')
            // 以roleName作為篩選條件
            .where('r.roleName like :name', { name: `%${query.name.toLowerCase()}%`})
            .orderBy('u.username', 'ASC')
            // Orderby也可以串聯
            .addOrderBy('u.email')
            // 跳過筆數,第一頁就為0,第二頁跳過pageSize筆
            .skip((query.page - 1) * query.pageSize)
            .take(query.pageSize) // 取pageSize筆數
            .getManyAndCount(); //回傳record 並 count筆數
     }

使用Postman測試

select部分欄位

有時候不想expose所有欄位,可以用select來篩選,當然也有object mapping的套件把部分欄位mapping到新的class上,但先就選擇部分欄位為例,假設只想要username, email, depName及roleName,其他如isActive則不需要

async getUsersByRoleName(query: UserQueryDTO){
          return await this.userRepo
            .createQueryBuilder('u')
            ...
            .skip((query.page - 1) * query.pageSize)
            .take(query.pageSize) // 取pageSize筆數
            .select([ //第一直覺只要列舉要的欄位
              'u.username',
              'u.email',
              'd.depName',
              'r.roleName',
            ])
            //.addSelect('u.password') // select 隱藏欄位
            // debug
            //.getSql();
            .getManyAndCount(); //回傳record 並 count筆數

     }

使用postman測試

錯誤訊息是找不到u_id,用getSql()來取得sql看哪裡有錯

SELECT "u"."username" AS "u_username", "r"."roleName" AS "r_roleName", "d"."depName" AS "d_depName" FROM "My_Users" "u" LEFT JOIN "my__users_roles_role" "u_r" ON "u_r"."myUsersId"="u"."id" LEFT JOIN "role" "r" ON "r"."id"="u_r"."roleId"  LEFT JOIN "Departments" "d" ON "d"."id"="u"."depId" WHERE "r"."roleName" like $1 ORDER BY "u"."username" ASC, "u"."id" DESC

原因是沒有SELECT u.id,我以為Primary key的選擇,TypeORM會自動產生,但沒有,所以要自己加,或是直接select alias

async getUsersByRoleName(query: UserQueryDTO){
          return await this.userRepo
            .createQueryBuilder('u')
            ...
            .skip((query.page - 1) * query.pageSize)
            .take(query.pageSize) // 取pageSize筆數
            .select([ //第一直覺只要列舉要的欄位
              'u.id',
              'u.username',
              'd.id',
              'd.depName',
              'r', // 選alias就會包含id了,只是所有欄位都會選取
              // 'r.id',
              //'r.roleName',
            ])
            //.addSelect('u.password') // select 隱藏欄位
            // debug
            //.getSql();
            .getManyAndCount(); //回傳record 並 count筆數

     }

使用postman測試

P.S.
try的過程也是會遇到額外錯誤,一直用getSQL()除錯,耗時XDDD

隱藏欄位

如果有一個欄位在大多數時候都不希望被select到,只有少數情況會用到,typeorm提供隱藏欄位的概念,在QueryBuilder中select entity或是Repository find預設不會被選到,則需要在欄位上設定,如User Entity的password欄位

新增password欄位

@Entity('My_Users') // 指定table name
export class User {
    @PrimaryGeneratedColumn()
    id: number;
    
    ...

    @Column({
        nullable:true, // 因為此欄位後來才加,不設定nullable無法新增此欄位
        length: 100,
        // 一般用repository.find不會出現此欄位
        // 在QueryBuilder中select entity也不會出現
        select: false, 
     })
     password: string;
}

![](https://i.imgur.com/e9R4wK9.png)

修改query, select User Entity

async getUsersByRoleName(query: UserQueryDTO){
          return await this.userRepo
            .createQueryBuilder('u')
            ...
            .skip((query.page - 1) * query.pageSize)
            .take(query.pageSize) // 取pageSize筆數
            .select([ //第一直覺只要列舉要的欄位
              'u', //直接select entity
              'd.id',
              'd.depName',
              'r', // 選alias就會包含id了,只是所有欄位都會選取
              // 'r.id',
              //'r.roleName',
            ])
            // debug
            //.getSql();
            .getManyAndCount(); //回傳record 並 count筆數

     }

用postman測試

User Entity所有欄位都出現,只有password欄位沒出現

修改query, 新增addSelect讓password出現

async getUsersByRoleName(query: UserQueryDTO){
          return await this.userRepo
            .createQueryBuilder('u')
            ...
            .skip((query.page - 1) * query.pageSize)
            .take(query.pageSize) // 取pageSize筆數
            .select([ //第一直覺只要列舉要的欄位
              'u', //直接select entity
              'd.id',
              'd.depName',
              'r', // 選alias就會包含id了,只是所有欄位都會選取
              // 'r.id',
              //'r.roleName',
            ])
            .addSelect('u.password') // select 隱藏欄位
            // debug
            //.getSql();
            .getManyAndCount(); //回傳record 並 count筆數

     }

使用postman測試

密碼欄位出現

Github source code


上一篇
Day19-TypeORM(六) Query Builder Select(上)
下一篇
Day21-TypeORM(八) RelationQueryBuilder(上)
系列文
讀官網文件邊走邊學nest.js31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言