Sequelize:从查询返回的实例方法和属性未定义

Sequelize: Instance Methods and Properties returned from Query are undefined

续集:6.6.2

Mysql2: 2.2.5

我已经像这样定义了我的 Model 并设置了这样的方法:

interface IUserAttributes {
  user_id: number;
  logon_name: string;
  user_password: string;
  full_name: string;
  disable_user: number;
  district_code: number;
  created_modified: Date;
}

interface IUserCreationAttributes extends Optional<IUserAttributes, 'user_id'> { }

export class User
  extends Model<IUserAttributes, IUserCreationAttributes>
  implements IUserAttributes {
  public user_id!: number;
  public logon_name!: string;
  public user_password!: string;
  public full_name!: string;
  public disable_user!: number;
  public district_code!: number;
  public created_modified!: Date;

  public readonly user_assigned_level: UserAssignedLevel;

  public static associations: {
    user_assigned_level: Association<User, UserAssignedLevel>
  }

  public toUserJSON: () => User;
  public generateAccessToken: (payload: IUser) => string;
  public generateRefreshToken: (payload: IUser) => string;
  public getRole: () => 'meter_reader' | 'evaluator' | null;

}

User.prototype.toUserJSON = function () {
  const keysToDelete = ['user_password'];
  const obj = this.toJSON();

  keysToDelete.forEach((key) => delete obj[key]);

  return obj;
}

User.prototype.getRole = function (): 'meter_reader' | 'evaluator' {
  const userLevel = this.user_assigned_level.user_level_id;
  let role = null;

  if (userLevel === 13) {
    role = 'meter_reader';
  } else if (userLevel === 9) {
    role = 'evaluator';
  }

  return role;
}

User.init(
  {
    user_id: {
      autoIncrement: true,
      type: DataTypes.SMALLINT,
      allowNull: false,
      primaryKey: true
    },
    logon_name: {
      type: DataTypes.STRING(20),
      allowNull: false
    },
    user_password: {
      type: DataTypes.STRING(20),
      allowNull: false
    },
    full_name: {
      type: DataTypes.STRING(100),
      allowNull: false
    },
    disable_user: {
      type: DataTypes.TINYINT.UNSIGNED,
      allowNull: false,
      defaultValue: 0
    },
    district_code: {
      type: DataTypes.CHAR(2),
      allowNull: true
    },
    created_modified: {
      type: DataTypes.DATE,
      allowNull: false,
      defaultValue: literal('CURRENT_TIMESTAMP')
    }
  },
  {
    sequelize: DBInstance,
    tableName: 'users',
    timestamps: false,
    underscored: true,
    defaultScope: {
      attributes: {
        exclude: ['user_password']
      }
    },
    scopes: {
      withoutPassword: {
        attributes: { exclude: ['user_password'] },
      }
    },
  }
);

// foreignKey of Model to target
User.hasOne(UserAssignedLevel, {
  foreignKey: 'user_id',
  as: 'user_assigned_level' // this determines the name in `associations`
});

当我查询用户并尝试使用我定义的 toUserJSON() 方法时,它失败了

const user = await User.findOne({
  include: {
     model: UserAssignedLevel,
     as: 'user_assigned_level',
     where: {
        [Op.or]: [
          { user_level_id: 9 },
          { user_level_id: 13 },
        ]
      },
    },
    where: {
      logon_name: username,
      disable_user: 0
    },
    attributes: {
       include: ['user_id', 'logon_name', 'user_password', 'disable_user'],
       // exclude: ['user_password']
    },
   });

   if (!user) {
     return next(new ErrorHandler(401, 'Incorrect credentials.'));
   }


   const result = user.toUserJSON(); // user.toUserJSON is not a function

当我在控制台中记录 user 实例的值时,它 return 是这样的。 当我尝试访问像 user_idlogon_name 这样的 属性 值时,它总是 return 未定义。我必须像 user.getDataValue('user_id') 一样使用 getDataValue() 来访问该字段。

User {
  dataValues: {
    user_id: 581,
    logon_name: 'cha',
    full_name: 'CHARISSE SUNGA',
    disable_user: 0,
    district_code: '9',
    created_modified: 2021-03-24T01:52:14.000Z,
    user_password: 'èÀ‘\x81k\x8D²pœUìOÌ:\x9D´',
    user_assigned_level: UserAssignedLevel {
      dataValues: [Object],
      _previousDataValues: [Object],
      _changed: Set(0) {},
      _options: [Object],
      isNewRecord: false,
      user_assigned_level_id: undefined,
      user_id: undefined,
      user_level_id: undefined,
      created_modified: undefined
    }
  },
  _previousDataValues: {
    user_id: 581,
    logon_name: 'cha',
    full_name: 'CHARISSE SUNGA',
    disable_user: 0,
    district_code: '9',
    created_modified: 2021-03-24T01:52:14.000Z,
    user_password: 'èÀ‘\x81k\x8D²pœUìOÌ:\x9D´',
    user_assigned_level: UserAssignedLevel {
      dataValues: [Object],
      _previousDataValues: [Object],
      _changed: Set(0) {},
      _options: [Object],
      isNewRecord: false,
      user_assigned_level_id: undefined,
      user_id: undefined,
      user_level_id: undefined,
      created_modified: undefined
    }
  },
  _changed: Set(0) {},
  _options: {
    isNewRecord: false,
    _schema: null,
    _schemaDelimiter: '',
    include: [ [Object] ],
    includeNames: [ 'user_assigned_level' ],
    includeMap: { user_assigned_level: [Object] },
    includeValidated: true,
    attributes: [
      'user_id',
      'logon_name',
      'full_name',
      'disable_user',
      'district_code',
      'created_modified',
      'user_id',
      'logon_name',
      'user_password',
      'disable_user'
    ],
    raw: true
  },
  isNewRecord: false,
  user_assigned_level: undefined,
  user_id: undefined,
  logon_name: undefined,
  user_password: undefined,
  full_name: undefined,
  disable_user: undefined,
  district_code: undefined,
  created_modified: undefined,
  toUserJSON: undefined,
  generateAccessToken: undefined,
  generateRefreshToken: undefined,
  getRole: undefined
}

如您所见,dataValues 之外的方法和属性都是未定义的。

对于遇到同样问题的任何人,我设法通过在 class 定义中设置方法来解决问题。

但是,像 this.username 那样直接访问属性仍然 return 未定义。您可以使用 getDataValue 方法 this.getDataValue('username')get 方法 const user = this.get({ plain:true })

访问属性
export class UserAuth
  extends Model<IUserAuthAttributes, IUserAuthCreationAttributes>
  implements IUserAuthAttributes {

  public user_auth_id!: number;
  public username!: string;
  public password!: string;
  public full_name!: string;
  public disable_user: number;
  public user_level_id!: number;
  public created_modified: string | Date;

  // Set the method here
   getRole() {
    const user = this.get({ plain: true });

    let role = null;

    if (user.user_level_id === 13) {
      role = 'meter_reader';
    } else if (user.user_level_id === 9) {
      role = 'evaluator';
    }

    return role;
  }
}