Sequelize in Node/Express - 'no such table: main.User` error - node.js

I'm trying to build a simple Node/Express app with Sequelize, but when I try to create a new record in my relational database, I am getting the error Unhandled rejection SequelizeDatabaseError: SQLITE_ERROR: no such table: main.User. Basically, I create a user in the Users table and then try to create a related address in the Addresses table - the user is successfully created but it fails with this error when creating the address... where is it getting the main prefix from in the table name? (full error readout below)...
First off, here's a rundown of my program...
My Sequelize version is Sequelize [Node: 6.8.1, CLI: 2.4.0, ORM: 3.29.0], and I used the Sequelize CLI command sequelize init to set up this portion of my project.
I am using SQLite3 for local development, and in config/config.json I have the development db defined as
"development": {
"storage": "dev.sqlite",
"dialect": "sqlite"
}
My user migration:
'use strict';
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
first_name: {
type: Sequelize.STRING
},
last_name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('Users');
}
};
and the address migration (abbreviated):
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('Addresses', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
address_line_one: {
type: Sequelize.STRING
},
UserId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: "User",
key: "id"
}
}
})
}
The user model:
'use strict';
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
first_name: DataTypes.STRING,
last_name: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
models.User.hasOne(models.Address);
}
}
});
return User;
};
and the address model:
'use strict';
module.exports = function(sequelize, DataTypes) {
var Address = sequelize.define('Address', {
address_line_one: DataTypes.STRING,
UserId: DataTypes.INTEGER
}, {
classMethods: {
associate: function(models) {
models.Address.hasOne(models.Geometry);
models.Address.belongsTo(models.User, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false
}
});
}
}
});
return Address;
};
finally, my route index.js:
router.post('/createUser', function(req, res){
var firstName = req.body.first_name;
var lastName = req.body.last_name;
var addressLineOne = req.body.address_line_one;
models.User.create({
'first_name': newUser.firstName,
'last_name': newUser.lastName
}).then(function(user){
return user.createAddress({
'address_line_one': newUser.addressLineOne
})
})
So when I try to post to /createUser, the User will successfully be created and the console will say that a new Address has been created (INSERT INTO 'Addresses'...), but the address is NOT created and the following error is logged:
Unhandled rejection SequelizeDatabaseError: SQLITE_ERROR: no such table: main.User
at Query.formatError (/Users/darrenklein/Desktop/Darren/NYCDA/WDI/projects/world_table/wt_test_app_1/node_modules/sequelize/lib/dialects/sqlite/query.js:348:14)
at afterExecute (/Users/darrenklein/Desktop/Darren/NYCDA/WDI/projects/world_table/wt_test_app_1/node_modules/sequelize/lib/dialects/sqlite/query.js:112:29)
at Statement.errBack (/Users/darrenklein/Desktop/Darren/NYCDA/WDI/projects/world_table/wt_test_app_1/node_modules/sqlite3/lib/sqlite3.js:16:21)
I've done this sort of thing with Sequelize once before a few months ago and it was successful, I cannot for the life of me figure out what I'm missing here. Why is the app looking for main.User, and how can I get it to look for the correct table? Thank you!

Aha! A small error has derailed my entire operation. In the migration files, references.model must be pluralized!
references: {
model: "Users",
key: "id"
}
Boom.

Related

how to write migrations to add foreignkey to already existing tables in sequelize

I have this already created two tables called User and Profile.
This is how my model for User looks like..
const Sequelize = require("sequelize");
const db = require("../db");
const User = db.define("User", {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: Sequelize.STRING,
allowNull: true,
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validator: {
isEmail: true,
},
},
});
module.exports = User;
and model for Profile looks like..
const Sequelize = require("sequelize");
const User = require("./User");
const db = require("../db");
const Profile = db.define("Profile", {
image: {
type: Sequelize.STRING,
},
description: {
type: Sequelize.TEXT,
},
});
module.exports = Profile;
Now I want to define a one-to-one relationship between User and Profile such that user will recieve a profileId column.
so i am defining it like this
Profile.hasOne(User, {
foreignKey: {
allowNull: false,
},
});
User.belongsTo(Profile);
Now i am not able to figure out how to write migrations for the newly added foreign key
can anyone help me please..
Thanks.
I got the answer. for someone who is confused like me here is the answer
since the User table already exists, migrations for the foreignkey will look like this
module.exports = {
async up(queryInterface, Sequelize) {
return await queryInterface.addColumn("Users", "ProfileId", {
type: Sequelize.INTEGER,
references: {
model: "Profiles",
key: "id",
},
});
},
async down(queryInterface, Sequelize) {
return await queryInterface.removeColumn("Users", "ProfileId", {
type: Sequelize.INTEGER,
references: {
model: "Profiles",
key: "id",
},
});
},
};
the Users in addColumn and removeColumn is the name of the table in which foreignkey was added.
the ProfileId is the name for foreignkey which you would have specified in hasOne.
hope this helps..

sequelize-cli db:migrate doesn't generate association table

I have a User model (with associated migration file created by sequelize-cli):
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
dispName: DataTypes.STRING,
email: DataTypes.STRING,
phoneNum1: DataTypes.STRING
}, {});
User.associate = function (models) { // associations added manually
User.belongsToMany(models.Role, { through: 'UserRoles', foreignKey: 'userId' });
};
return User;
};
here's the generated migration file:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
cognitoId: { // modified: was an auto-incrementing integer
allowNull: false,
primaryKey: true,
type: Sequelize.STRING(100)
},
dispName: {
type: Sequelize.STRING(100) // modified: was just plain STRING
},
email: {
type: Sequelize.STRING(100) // modified: was just plain STRING
},
phoneNum1: {
type: Sequelize.STRING(15) // modified: was just plain STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users');
}
};
and a Role model (with associated migration file created by sequelize-cli):
'use strict';
module.exports = (sequelize, DataTypes) => {
const Role = sequelize.define('Role', {
name: DataTypes.STRING
}, {});
Role.associate = function (models) { // associations added manually
Role.belongsToMany(models.User, { through: 'UserRoles', foreignKey: 'roleId' });
};
return Role;
};
here's the generated migration file for Role:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Roles', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING(100), // modified: was just plain STRING
unique: true // Added manually
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Roles');
}
};
When I run sequelize-cli db:migrate, the table UserRoles is not created. Why is that?
The Associations page of the Sequelize manual seems to suggest that defining the associations in the model file is all that is required...
Research:
I seem to have done what is suggested in this answer to the question Sequelize not creating model association columns but doesn't seem to be working for me (the answer isn't accepted either).
Not quite what I need: Querying association tables in Sequelize
Nor this: Sequelize how to use association table?

NodeJs + Sequelize + Express extra association key addedwhen query-ing

I have 2 tables: Countries and Spots. A country can have many spots and a spot belongs to one country.
I have generated the migrations necessary with sequelize for the 2 tables:
Countries.js
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Countries', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
allowNull: false,
unique: true,
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
defaultValue: Sequelize.literal('NOW()'),
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
defaultValue: Sequelize.literal('NOW()'),
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Countries');
}
};
Spots.js
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Spots', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
allowNull: false,
type: Sequelize.STRING
},
wind: {
type: Sequelize.FLOAT
},
country_id: {
type: Sequelize.INTEGER,
references: {
model: 'Countries', // name of Target table
key: 'id', // key in Target table that we're referencing
},
onDelete: 'CASCADE',
},
createdAt: {
allowNull: false,
defaultValue: Sequelize.literal('NOW()'),
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
defaultValue: Sequelize.literal('NOW()'),
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Spots');
}
};
Everything works ok. I define some routes and some controllers and I try to do Spots.findAll() in my controller
const models = require('../models/index')
const Spot = models.Spot
exports.index = async (req, res, next) => {
const spots = await Spot.findAll()
res.status(200).json(spots)
}
However the query Spot.findAll() tries to ask for CountryId which is a key that obviously doesn't exist and I do not wish for it to exist.
Executing (default): SELECT `id`, `name`, `wind`, `country_id`, `createdAt`, `updatedAt`, `CountryId` FROM `Spots` AS `Spot`;
(node:13027) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: Unknown column 'CountryId' in 'field list'
These are the spot and countries models:
Country.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const Country = sequelize.define('Country', {
name: DataTypes.STRING
}, {});
Country.associate = function(models) {
// associations can be defined here
Country.hasMany(models.Spot)
};
return Country;
};
Spot.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const Spot = sequelize.define('Spot', {
name: DataTypes.STRING,
wind: DataTypes.FLOAT,
country_id: DataTypes.INTEGER
}, {});
Spot.associate = function(models) {
// associations can be defined here
Spot.belongsTo(models.Country, {
foreignKey: 'country_id'
});
Spot.hasMany(models.Favorite)
};
return Spot;
};
I added the foreign_key attribute to belongs_to as I thought that the error surely comes from the associations(I still think it does).
Why does it happen and how to fix it?
The problem is because you are mixing everything here please follow one convention either camelCase or snack_case.
Write country_id as countryId and change your table names to lowercase and you will good to go.

Problem setting up Sequelize association - query with 'include' is failing

I'm new to Sequelize and trying to test if an n:m association I set up between two models, User and Podcast, is working. When I try to run this query, I get some kind of DB error that isn't specific about what's wrong:
User.findOne({
where: { id: id },
include: [{ model: Podcast }]
});
Does anyone know what I'm messing up? I suspect there's something wrong in how I've set up the association, like I'm referencing the names of tables slightly incorrectly, but the migration to create the association worked.
Here's my User.js model file:
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
photo: {
type: DataTypes.STRING
}
});
User.associate = function(models) {
// associations can be defined here
User.belongsToMany(models.Podcast, {
through: 'user_podcast'
});
};
return User;
};
And here's my Podcast.js file:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Podcast = sequelize.define('Podcast', {
id: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false
},
title: {
type: DataTypes.STRING,
allowNull: false
},
thumbnail: {
type: DataTypes.STRING
},
website: {
type: DataTypes.STRING
}
});
Podcast.associate = function(models) {
// associations can be defined here
Podcast.belongsToMany(models.User, {
through: 'user_podcast'
});
};
return Podcast;
};
And here's the migration I ran to join the two tables:
'use strict';
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('user_podcast', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
}
},
podcastId: {
type: Sequelize.STRING,
references: {
model: 'Podcasts',
key: 'id'
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('user_podcast');
}
};
And here's the project on Github for further reference:
https://github.com/olliebeannn/chatterpod
You don't need to create a migration for the M:N table. Now you have something wrong on your user_podcast model. If you are setting a M:N relation between to tables your primary key will be the combination between the foreign key from these two models. If you still want a single id primary key for your table, then you won't use belongsToMany instead use hasMany on user and podcast models pointing to a new model user_podcast.
As far as I see on your first query, it seems that you really need a M:N relation so you can define the model as you do with user and podcast like this:
module.exports = (sequelize, DataTypes) => {
const UserPodcast = sequelize.define('user_podcast', {
userId: {
// field: 'user_id', #Use 'field' attribute is you have to match a different format name on the db
type: DataTypes.INTEGER
},
podcastId: {
// field: 'podcast_id',
type: DataTypes.INTEGER
},
});
UserPodcast.associate = function(models) {
models.User.belongsToMany(models.Podcast, {
as: 'podcasts', //this is very important
through: { model: UserPodcast },
// foreignKey: 'user_id'
});
models.Podcast.belongsToMany(models.User, {
as: 'users',
through: { model: UserPodcast },
// foreignKey: 'podcast_id'
});
};
return UserPodcast;
};
I do prefer to have the belongsToMany associations on the save function where I define the join model, and you have to notice that I used as: attribute on the association. This is very important because this will help sequelize to know which association are you referring on the query.
User.findOne({
where: { id: id },
include: [{
model: Podcast,
as: 'podcasts' //here I use the previous alias
}]
});

Creating associations in Sequelize migration

Nodejs. Sequelize 4.41. Try to make 2 models with relation many-to-many through another table. Running with sequelize-cli, for example...
sequelize model:generate --name Camera --attributes name:string,sn:string
Here is models
// Camera model
'use strict';
module.exports = (sequelize, DataTypes) => {
const Сamera = sequelize.define('Сamera', {
name: DataTypes.STRING,
sn: DataTypes.STRING
}, {});
Сamera.associate = function(models) {
// associations can be defined here
Camera.belongsToMany(models.Relay, {through: 'CameraRelay'});
};
return Сamera;
};
And
// Relay model
'use strict';
module.exports = (sequelize, DataTypes) => {
const Relay = sequelize.define('Relay', {
name: DataTypes.STRING,
sn: DataTypes.STRING,
channel: DataTypes.INTEGER
}, {});
Relay.associate = function(models) {
// associations can be defined here
Relay.belongsToMany(models.Camera, {through: 'CameraRelay'});
};
return Relay;
};
In documentation there are phrase
Belongs-To-Many associations are used to connect sources with multiple targets. Furthermore the targets can also have connections to multiple sources.
Project.belongsToMany(User, {through: 'UserProject'});
User.belongsToMany(Project, {through: 'UserProject'});
This will
create a new model called UserProject with the equivalent foreign keys
projectId and userId.
Migrations is
// create-relay
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Relays', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
sn: {
type: Sequelize.STRING
},
channel: {
type: Sequelize.INTEGER
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Relays');
}
};
And
//create camera
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Сameras', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
sn: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Сameras');
}
};
Why it doesn't create model CameraRelay and doesn't create migration for same model when I running migrate?
I guess the misunderstanding is about sync vs migration: great part of documentation you are referring to, is using the sync method to create all tables and associations starting from models.
When you are using migrations, you are creating db all of your table/columns/associations using migration files (and in my hopinion, this is a better way for something that is going to production).
To understand the difference, just look at your camera model vs your camera migration file:
the model has only name and sn properties defined
the migration file has of course name and sn, but it has id, createdAt and updatedAt too.
Migrations are file with the aim of change your db in a safe way, allowing you to rollback to any point in the past.
So, back to your problem, you have to:
create a new migration file to create your new CameraRelay table, with foreign keys to both Camera and Relay tables
update your current Camera migration file with one-to-many relation to CameraRelay table
update your current Relay migration file with one-to-many relation to CameraRelay table
CameraRelay migration example:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('CameraRelays', {
cameraId: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Relay',
key: 'id'
}
},
relayId: {
primaryKey: true,
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Camera',
key: 'id'
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('CameraRelays');
}
};

Resources