sequelize.jsnode-sqlite3

Sequelize Many to Many basics - "no such table"


In my first attempt to define a Many to Many relationship in Sequelize (v6, SQLITE3 v5) I'm already not getting very far. My setup is very simple.

Here is the code in my index.js that causes the error (setPlayers() instead of addPlayer() gives roughly the same error):

const cup = await Cup.findOne({ where: { thread: interaction.message.id }});
const player = await Player.findOne({ where: { id: interaction.user.id } });
await cup.addPlayer(player);

and the error message. As you can see CupPlayers is what I want my junction table to be.

[Error: SQLITE_ERROR: no such table: CupPlayers] {
    errno: 1,
    code: 'SQLITE_ERROR',
    sql: "SELECT `CupId`, `PlayerId`, `createdAt`, `updatedAt`, `cupId`, `playerId` FROM `CupPlayers` AS `CupPlayers` WHERE `CupPlayers`.`cupId` = 
1 AND `CupPlayers`.`playerId` IN ('23485757129835978');"

here are my models:

Player.js

module.exports = (sequelize, DataTypes) => {
    return sequelize.define('player', {
        id:     {type: DataTypes.STRING, primaryKey: true},
    }, {
        timestamps: false,
    });
};

Cup.js

module.exports = (sequelize, DataTypes) => {
    return sequelize.define('cup', {
        id:             {type: DataTypes.INTEGER, primaryKey: true},
        date:           {type: DataTypes.DATE, defaultValue: null},
        thread:         {type: DataTypes.STRING, defaultValue: null},
        list_message:   {type: DataTypes.STRING, defaultValue: null},
        reminder:       {type: DataTypes.STRING, defaultValue: null},
        is_open:        {type: DataTypes.BOOLEAN, defaultValue: true},
    }, {
    });
};

dbObjects.js for relations. As you can see I want Sequelize to automatically create the junction table. (when I try making my own junction table the error is no such table: main.undefined, so not much different)

const Sequelize = require('sequelize');

const sequelize = new Sequelize('a', 'b', 'c', {
    host: 'localhost',
    dialect: 'sqlite',
    logging: false,
    storage: 'cup_database.sqlite',
});

const Player = require('./models/Player.js')(sequelize, Sequelize.DataTypes);
const Cup = require('./models/Cup.js')(sequelize, Sequelize.DataTypes);

Cup.belongsToMany(Player, { through: 'CupPlayers' });
Player.belongsToMany(Cup, { through: 'CupPlayers' });

module.exports = { Player, Cup };

and finally dbInit.js to sync/initialise the database:

const Sequelize = require('sequelize');

const sequelize = new Sequelize('a', 'b', 'c', {
    host: 'localhost',
    dialect: 'sqlite',
    logging: false,
    storage: 'cup_database.sqlite',
});

require('./models/Player.js')(sequelize, Sequelize.DataTypes);
require('./models/Cup.js')(sequelize, Sequelize.DataTypes);

const force = process.argv.includes('--force') || process.argv.includes('-f');

sequelize.sync({ force }).then(async () => {
    
    const init = [
        Player.upsert({ id: '23485757129835978' })
    ];

    await Promise.all(init);
    console.log('Database synced');
    sequelize.close();
    
}).catch(console.error);

Overall a very simple setup, pretty much just copy pasted from the Sequelize and discord.js guides. I haven't had these kinds of problem with the other relationships and I have no idea what the error message means. I'd appreciate any help.


Solution

  • You registered models twice:

    1. dbObjects.js (model registration along with their associations);
    2. dbInit.js (model registration WITHOUT associations once again).

    So all in all while dbInit.js is executed all models were registered once again without their associations and thus sync did not create a junction table.

    All you need is to use models from dbObjects in dbInit and remove lines with a direct model registration from models folder.

    const Sequelize = require('sequelize');
    
    const sequelize = new Sequelize('a', 'b', 'c', {
        host: 'localhost',
        dialect: 'sqlite',
        logging: false,
        storage: 'cup_database.sqlite',
    });
    
    const { registerModels } = require('./dbObjects');
    
    const { Player, Cup } = registerModels(sequelize);
    
    const force = process.argv.includes('--force') || process.argv.includes('-f');
    
    sequelize.sync({ force }).then(async () => {
        const init = [
            Player.upsert({ id: '23485757129835978' })
        ];
    
        await Promise.all(init);
        console.log('Database synced');
        sequelize.close();
        
    }).catch(console.error);