Search code examples
node.jssequelize.jsassociationsone-to-many

Insert into one-to-many relationship table using sequelize with existing foreign key


I am having the following models:

Sports.init({
        name: {
            type: DataTypes.STRING,
            unique: true,
            allowNull: false
        }
    }, {sequelize, tableName: 'sports'});
    
Leagues.init({
        name: {
            type: DataTypes.STRING,
            unique: true,
            allowNull: false
        }
    }, {sequelize, tableName: 'leagues'});

The association between them is the following.

Sports.Leagues = Sports.hasMany(Leagues, {foreignKey: {name: "sports_id", allowNull: false}, sourceKey: "id"});
Leagues.Sports = Leagues.belongsTo(Sports, {foreignKey: {name: "sports_id", allowNull: false}, targetKey: "id"});

I already have a record in the Sports table: {name: "Basketball", id: 1} I want to create a record in the Leagues table referencing this already existing sports record. How can I do that with one function? I went through the documentation, but did not find anything appropriate there. I know I would be able to do it the following way, in case if the record, which I am referencing to, does not exist:

await Leagues.create({name: leagueName, espn_name: espnName, Sport: {name: "Basketball"}}, {include: Leagues.Sports});

However, I did not find anything about how to do it, if the foreign key already exists, besides manually doing something like this:

await Sports.findOne({where: {name: sportName}}).then((res) => {
        if(res) {
            return Leagues.create({name: leagueName, espn_name: espnName, sports_id: res.get("id")});
        }
    });

For me, it seems like too much code for a relatively simple operation. Is there any "smarter" or shorter way of doing that? Thank you in advance!


Solution

  • I found similar question on stackoverflow. So it seems like there is no other way of doing that other than manually finding id and then attaching it directly to the new record. However I made a shortcut in order to handle such queries more easily. So I created new class, which extended from the sequelize model class and added new static function which handles fetching of id by itself:

    export class CustomModel extends Model {
        static async getId<M extends Model>(attributes: M['_creationAttributes']) {
            const res = await this.findOne({where: attributes});
            if(!res) {
                throw new Error(`Can not find id of the record in the table ${this.tableName}`);
            }
            return res.get("id")
        }
    }
    

    And my models now extend from this class:

    export class Sports extends CustomModel{
        static Leagues: HasMany<Sports, Leagues>;
    }
    
    Sports.init({
            name: {
                type: DataTypes.STRING,
                unique: true,
                allowNull: false
            }
        }, {sequelize, tableName: 'sports'});
    

    So now it is possible to add new records with already existing key with less code:

     await Leagues.create({name: "u", sports_id: await Sports.getId({name: "Basketball"})});