Search code examples
typeormnode.js-typeorm

Return ONLY selected fields within a TypeORM find request


I'm struggling in returning only selected fields in my TypeORM find request.

Assuming the following request


const data = await AppDataSource.manager.find(User, {
    select: {
      id: true,
      hash: true,
      firstname: true,
      lastname: false,
    },
    take: 10, // Just here to shrink dataset
  });

The script works pretty well excepted that it return every field of my model, with default value initialized.

[
  User {
    prefix: 'usr',
    hash: 'usr_835b0ad2-XXXXXX',
    email: undefined,
    accountValidated: false,
    role: 'free',
    myKeyOne: true,
    myKeyTwo: false,
    gender: 'unspecified',
    lastConnexion: 2023-01-19T10:11:02.733Z,
    pendingDeletion: false,
    deletionDate: undefined,
    firstname: 'Clément',
    lastname: undefined,
    password: undefined,
    facebookId: undefined,
    googleId: undefined,
    id: 158
  },
  ...
]

Of course, it's not usable as it, because I have extensive relations, and thus the payload would be extremely heavy.

Are you aware of a method / a way to remove all unnecessary fields ? i.e. I'm expecting

[
 User {
    id: 124,
    hash: 'urs_XXXX',
    firstname: 'Clément',
 },
 ...
] 

Solution

  • After hours of researches I've finally found out why it behaved like this.

    TypeORM relies on class definitions and typescript so... if you have typescript default values OR if you have rewrite your constructor, all the "default" properties are injected.

    Assuming a User model

    You should not do

    @Entity({ name: 'users' })
    class User {
      
      @Column()
      firstname?: string;
    
      @Column({ nullable: true })
      lastname?: string;
    
      @Column({ unique: true, nullable: false })
      email!: string;
    
      @Column({ name: 'account_validated', nullable: false})
      accountValidated?: boolean = false
    
      //Your other fields...
    }
    

    You should do

    @Entity({ name: 'users' })
    class User {
      
      @Column()
      firstname?: string;
    
      @Column({ nullable: true })
      lastname?: string;
    
      @Column({ unique: true, nullable: false })
      email!: string;
    
      // Use default argument of the decorator
      @Column({ name: 'account_validated', nullable: false, default: false})
      accountValidated?: boolean
    
      //Your other fields...
    }
    

    And if you need in some way to init a default, then create a public static method which return the Entity instead of using the constructor.

    @Entity({ name: 'users' })
    class User {
      //...fields 
      public static init(...params): User {
        let _user = new User()
        //...populate your object
        return _user
    
      }
    
    }