Mogens TrasherDK
Mogens TrasherDK

Reputation: 680

Node.js Sequelize virtual column pulling value from other model

I'm working with Sequelize 5.7, trying to utilize virtual datatype,
to pull related information into a model.

Given simplified company and user models, how do I get company.name
into user.companyname ?

company

  let Schema = sequelize.define(
    "company",
    {
      id: {
        type: DataTypes.INTEGER.UNSIGNED,
        autoIncrement: true,
        primaryKey: true
      },
      name: {
        type: DataTypes.STRING(45)
      }
    }
  );

user

  let Schema = sequelize.define(
    "user",
    {
      id: {
        type: DataTypes.INTEGER.UNSIGNED,
        autoIncrement: true,
        primaryKey: true
      },
      login: {
        type: DataTypes.STRING(45),
        unique: true
      },
      company: {
          type: DataTypes.INTEGER.UNSIGNED,
          references: {
            model: sequelize.model('company'),
            key: 'id'
          }
      },

      /* This companyname contruct is pure fantasy, and the target of my question */

      companyname: {
        type: new DataTypes.VIRTUAL(DataTypes.STRING,['company']),
          references: {
            model: 'company',
            key: 'name'
          }
      }
    }
  );

Upvotes: 4

Views: 10706

Answers (2)

Eduardo Santos
Eduardo Santos

Reputation: 21

I solved the problem by using type: DataTypes.VIRTUAL in model

const { Model, DataTypes } = require('sequelize');

class User extends Model {
    static init(sequelize) {
        super.init({
            id: {
                type: DataTypes.INTEGER.UNSIGNED,
                autoIncrement: true,
                primaryKey: true
            },
            login: {
                type: DataTypes.STRING(45),
                unique: true
            },
            company_id: {
                type: DataTypes.INTEGER.UNSIGNED,
            },
            companyname:{
                type: DataTypes.VIRTUAL,
                get() {
                    return this.Company?.get().name;
                },
                set(/*value*/) {
                    throw new Error('Do not try to set the `companyname` value!');
                }
            },
        }, {
            sequelize
        })
    }
    static associate(models) {
        this.belongsTo(Company, {
          foreignKey: 'company_id',
        });
    }
}

module.exports = User;

to search just include the association :

User.findAll({ include: Company })

I usually create each model using 'class' in different files, but if you need, just include the code below in the @jalex19 solution

companyname:{
    type: DataTypes.VIRTUAL,
    get() {
        return this.Company?.get().name;
    },
    set(/*value*/) {
        throw new Error('Do not try to set the `fullName` value!');
    }
},

Upvotes: 2

jalex19
jalex19

Reputation: 201

In your case, I think it is a better idea to use a relationship (an association)

Sequelize Associations

const User = sequelize.define('user', {
  id: {
    type: DataTypes.INTEGER.UNSIGNED,
    autoIncrement: true,
    primaryKey: true
  },
  login: {
    type: DataTypes.STRING(45),
    unique: true
  },
  company_id: {
    type: DataTypes.INTEGER.UNSIGNED,
  },
});

const Company = sequelize.define('company', {
  id: {
    type: DataTypes.INTEGER.UNSIGNED,
    autoIncrement: true,
    primaryKey: true,
  },
  name: {
    type: DataTypes.STRING,
  },
});

User.belongsTo(Company, {
  foreignKey: 'company_id', // you can use this to customize the fk, default would be like companyId
});

Company.hasMany(User);

Then when calling your model you do something like:

User.findAll({ include: Company }).then(users => console.log(users));

Upvotes: 3

Related Questions