Sequelize returns "Unknown column" when including tables - mysql

The idea is to get numbers that as associated with jobs on the call server. Each job has a bunch of numbers associated with it. When somebody calls back, I need to get the job associated with the caller ID.
The query that causes the issue:
// Look for messages to play
db.job.find( {
'where': { 'status' : [ 'new', 'inprogress', 'done' ] },
// 'limit' : 1, // Obviously
'order' : [[ 'jobID' , 'DESC' ]], // Latest
'include' : [
{
'model' : db.number,
'where' : { 'number' : this.number }
}
]
} ).complete( ... );
The database snippets:
var job = sequelize.define( 'job', {
'id': {
type: Sequelize.INTEGER( 10 ),
field: 'job_id',
allowNull: false,
primaryKey: true,
autoIncrement: true
},
'externalID' : {
type: Sequelize.STRING( 45 ),
field: 'external_id',
allowNull: false,
unique: true,
validate: {
notEmpty: true
}
},
'status' : {
type: Sequelize.STRING( 16 ),
field: 'status',
allowNull: false,
defaultValue: 'processing'
},
'filename' : {
type: Sequelize.STRING( 64 ),
field: 'filename',
allowNull: true
}
}, {
'createdAt' : 'created',
'updatedAt' : 'modified',
'tableName' : 'jobs'
} );
var number = sequelize.define( 'number', {
'id': {
type: Sequelize.BIGINT( 20 ),
field: 'number_id',
allowNull: false,
primaryKey: true,
autoIncrement: true
},
'jobID': {
type: Sequelize.INTEGER( 10 ),
field: 'job_id',
allowNull: false
},
'externalID' : {
type: Sequelize.STRING( 45 ),
field: 'external_id',
allowNull: false,
unique: true,
validate: {
notEmpty: true
}
},
'number' : {
type: Sequelize.STRING( 16 ),
field: 'number',
allowNull: false,
validate: {
notEmpty: true
}
},
'extension' : {
type: Sequelize.STRING( 16 ),
field: 'extension',
allowNull: true
},
'status' : {
type: Sequelize.STRING( 16 ),
field: 'status',
allowNull: false,
defaultValue: 'new'
},
'lastCall' : {
type: Sequelize.DATE,
field: 'last_call',
allowNull: true
},
'tries' : {
type: Sequelize.INTEGER,
field: 'tries',
allowNull: false,
defaultValue: 0
},
}, {
'createdAt' : 'created',
'updatedAt' : 'modified',
'tableName' : 'numbers'
} );
job.hasMany( number, { 'foreignKey' : 'job_id' } );
number.belongsTo( job, { 'foreignKey' : 'job_id' } );
Somehow the query it generates is this:
SELECT `job`.*,
`numbers`.`number_id` AS `numbers.id`,
`numbers`.`job_id` AS `numbers.jobID`,
`numbers`.`external_id` AS `numbers.externalID`,
`numbers`.`number` AS `numbers.number`,
`numbers`.`extension` AS `numbers.extension`,
`numbers`.`status` AS `numbers.status`,
`numbers`.`last_call` AS `numbers.lastCall`,
`numbers`.`tries` AS `numbers.tries`,
`numbers`.`created` AS `numbers.created`,
`numbers`.`modified` AS `numbers.modified`,
`numbers`.`job_id` AS `numbers.job_id`
FROM
(SELECT `job`.`job_id` AS `id`,
`job`.`external_id` AS `externalID`,
`job`.`status`,
`job`.`filename`,
`job`.`created`,
`job`.`modified`
FROM `jobs` AS `job`
WHERE `job`.`status` IN ('new',
'inprogress',
'done')
AND
(SELECT `job_id`
FROM `numbers` AS `numbers`
WHERE `job`.`id` = `numbers`.`job_id`
AND `numbers`.`number` IN ('5556656565') LIMIT 1) IS NOT NULL
ORDER BY `job`.`jobID` DESC LIMIT 1) AS `job`
INNER JOIN `numbers` AS `numbers` ON `job`.`id` = `numbers`.`job_id`
AND `numbers`.`number` IN ('5556656565')
ORDER BY `job`.`jobID` DESC;
Which as you can see by the table structure is giving this error:
error: Callback: Error fetching job via number.
SequelizeDatabaseError: ER_BAD_FIELD_ERROR: Unknown column 'job.id' in
'where clause'
Where have I gone wrong here?

There seems to be an open issue about it, actually.
https://github.com/sequelize/sequelize/issues/3403

Related

how to apply delete in the many to many relation in sequalize

These are the three models.
export const UserPost = sequelize.define(
"user_post",
{
id: {
type: DataTypes.INTEGER,
field: "id",
autoIncrement: true,
primaryKey: true,
},
userId: {
type: DataTypes.INTEGER,
field: "user_id",
},
postId: {
field: "post_id",
type: DataTypes.INTEGER,
},
},
{
freezeTableName: true,
timestamps: true,
createdAt: "created_on",
updatedAt: "updated_on",
}
);
User.belongsToMany(Post, {
through: UserPost,
foreignKey: "userId",
});
Post.belongsToMany(user, {
through: UserPost,
foreignKey: "postId",
});
export default UserPost;
User
export const User = sequelize.define(
"user_post",
{
userId: {
type: DataTypes.INTEGER,
field: "user_id",
autoIncrement: true,
primaryKey: true,
},
},
{
freezeTableName: true,
timestamps: true,
createdAt: "created_on",
updatedAt: "updated_on",
}
);
export default User;
Post
export const Post = sequelize.define(
"user_post",
{
postId: {
type: DataTypes.INTEGER,
field: "post_id",
autoIncrement: true,
primaryKey: true,
},
},
{
freezeTableName: true,
timestamps: true,
createdAt: "created_on",
updatedAt: "updated_on",
}
);
export default Post;
I have two record in the table User with the Id 1 ,3
I have one record in the table Post with the Id 2
I have two record in the table userPost but when I try to delete the record from the table User with the Id 1 and it delete the both two record from the userPost table.
usePost
1 2
3 2
the delete query that I used to delete the records from the table.
const res = await User.destroy({
where: { userId },
cascade: true,
truncate: false,
});

Sequelize join two columns of one table to the same column of another table

I have a table Relation with columns userId1 and userId2 it basically stores the relation between two users, userId1 and userId2 is foreign key here referenced from the User tables id (PK) column.
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
userId1: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
},
userId2: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
},
status: {
type: DataTypes.ENUM,
},
Then there is another table Posts containing information about posts.
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
content: {
type: DataTypes.TEXT,
allowNull: false,
},
postedBy: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
},
I want to get lists of post of only those user who have a relation with me like friends, means my id lets suppose is 1 and it is in userId1 column and userId2 column has id in it, then I want to fetch all posts of value 2 from posts postedBy column.
This case can be vice versa as my id can be in userId2 column and I need to get all posts of the user whose value is in userId1 column.
I have read through all the questions and answers like multiple associations but it is just not working for me.
This is my associations in Posts model
Posts.hasOne(RelationModel, {
foreignKey: 'userId1',
sourceKey: 'postedBy',
as: 'first',
})
Posts.hasOne(RelationModel, {
foreignKey: 'userId2',
sourceKey: 'postedBy',
as: 'second',
})
Below is my include array.
include:[
{
model: RelationModel,
as: 'first',
where: {
status: 'accepted',
[Op.or]: [
{ userId1: request.user.id },
{ userId2: request.user.id },
],
},
},
{
model: RelationModel,
as: 'second',
where: {
status: 'accepted',
[Op.or]: [
{ userId1: request.user.id },
{ userId2: request.user.id },
],
},
}
]
The query being generated from this is below, where 151 is the logged in user id, means my id
SELECT
`posts`.*,
`first`.*,
`second`.*
FROM
`posts` AS `posts`
INNER JOIN
`relations` AS `first` ON `posts`.`postedBy` = `first`.`userId1`
AND (`first`.`userId1` = 151
OR `first`.`userId2` = 151)
AND `first`.`status` = 'accepted'
INNER JOIN
`relations` AS `second` ON `posts`.`postedBy` = `second`.`userId2`
AND (`second`.`userId1` = 151
OR `second`.`userId2` = 151)
AND `second`.`status` = 'accepted'
WHERE
`posts`.`deletedAt` IS NULL
ORDER BY `posts`.`id` ASC , `posts`.`id` ASC;
But the query I want to build is below
SELECT
`posts`.*,
`first`.*
FROM
`posts` AS `posts`
INNER JOIN
`relations` AS `first` ON (`posts`.`postedBy` = `first`.`userId2`
OR `posts`.`postedBy` = `first`.`userId1`)
AND (`first`.`userId1` = 151
OR `first`.`userId2` = 151)
AND `first`.`isFriend` = TRUE
AND `first`.`status` = 'accepted'
WHERE
`posts`.`deletedAt` IS NULL
ORDER BY `posts`.`id` ASC , `posts`.`id` ASC;
How to construct this query in sequelize?
You need to specify a unique as keyword for each relationship in the association as well as on the include for your query.
Posts.hasOne(RelationModel, {
foreignKey: 'userId1',
sourceKey: 'postedBy',
as: 'first',
});
Posts.hasOne(RelationModel, {
foreignKey: 'userId2',
sourceKey: 'postedBy',
as: 'second',
});
Then when you query you specify the unique as that identifies the relationship for the join
Post.findByPk(id, {
include: [{
model: RelationModel,
as: 'first',
},
{
model: RelationModel,
as: 'second',
}],
});

error in sequelize > "name": "SequelizeEagerLoadingError"

I have two tables:
//User.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define("User", {
userId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
email: {
type: DataTypes.STRING,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
defaultValue: "",
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
chapterId: {
type: DataTypes.STRING,
},
});
User.associate = (models) => {
User.belongsTo(models.Chapter, {
foreignKey: "chapterId",
targetKey: "chapterId",
as: "chapter",
});
};
return User;
};
and
//chapter table
module.exports = (sequelize, DataTypes) => {
const Chapter = sequelize.define("Chapter", {
chapterId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
chapterName: {
type: DataTypes.STRING,
allowNull: false,
},
isChapterLocal: {
type: DataTypes.BOOLEAN,
allowNull: false,
},
});
Chapter.associate = (models) => {
};
return Chapter;
};
and i am trying to fetch users with chapters included into it.
let getAll = async (req, res) => {
try {
const userData = await db.User.findAll({
include: [
{
model: Chapter,
as: "chapter",
},
],
});
res.send(userData);
} catch (e) {
res.send(e);
}
};
how to include chapter id and chapter name from chapter table, as present in chapterId row for user table.
I am new to sequelize and MySQL and am unsure if the relation i have defined in the user model is good.
Do we need to define associations in both tables.
It should work as expected. E.g.
import { sequelize } from '../../db';
import { Model, DataTypes } from 'sequelize';
class User extends Model {}
User.init(
{
userId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
email: {
type: DataTypes.STRING,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
defaultValue: '',
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
chapterId: {
type: DataTypes.STRING,
},
},
{ sequelize, modelName: 'User' },
);
class Chapter extends Model {}
Chapter.init(
{
chapterId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
chapterName: {
type: DataTypes.STRING,
allowNull: false,
},
isChapterLocal: {
type: DataTypes.BOOLEAN,
allowNull: false,
},
},
{ sequelize, modelName: 'Chapter' },
);
User.belongsTo(Chapter, { foreignKey: 'chapterId', targetKey: 'chapterId', as: 'chapter' });
(async function test() {
try {
await sequelize.sync({ force: true });
// seed
await User.create(
{
userId: '1',
email: 'example#gmail.com',
firstName: 'Lin',
lastName: 'Du',
password: '123',
chapter: {
chapterId: '1',
chapterName: 'ok',
isChapterLocal: false,
},
},
{ include: [{ model: Chapter, as: 'chapter' }] },
);
// test
const userData = await User.findAll({
include: [{ model: Chapter, as: 'chapter' }],
raw: true,
});
console.log('userData:', userData);
} catch (error) {
console.log(error);
} finally {
sequelize.close();
}
})();
The execution results:
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Chapter" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Chapter" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Chapter" ("chapterId" VARCHAR(255) NOT NULL UNIQUE , "chapterName" VARCHAR(255) NOT NULL, "isChapterLocal" BOOLEAN NOT NULL, PRIMARY KEY ("chapterId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Chapter' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "User" ("userId" VARCHAR(255) NOT NULL UNIQUE , "email" VARCHAR(255), "firstName" VARCHAR(255) NOT NULL, "lastName" VARCHAR(255) DEFAULT '', "password" VARCHAR(255) NOT NULL, "chapterId" VARCHAR(255) REFERENCES "Chapter" ("chapterId") ON DELETE NO ACTION ON UPDATE CASCADE, PRIMARY KEY ("userId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'User' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "Chapter" ("chapterId","chapterName","isChapterLocal") VALUES ($1,$2,$3) RETURNING *;
Executing (default): INSERT INTO "User" ("userId","email","firstName","lastName","password","chapterId") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;
Executing (default): SELECT "User"."userId", "User"."email", "User"."firstName", "User"."lastName", "User"."password", "User"."chapterId", "chapter"."chapterId" AS "chapter.chapterId", "chapter"."chapterName" AS "chapter.chapterName", "chapter"."isChapterLocal" AS "chapter.isChapterLocal" FROM "User" AS "User" LEFT OUTER JOIN "Chapter" AS "chapter" ON "User"."chapterId" = "chapter"."chapterId";
userData: [ { userId: '1',
email: 'example#gmail.com',
firstName: 'Lin',
lastName: 'Du',
password: '123',
chapterId: '1',
'chapter.chapterId': '1',
'chapter.chapterName': 'ok',
'chapter.isChapterLocal': false } ]
Check the database:
node-sequelize-examples=# select * from "User";
userId | email | firstName | lastName | password | chapterId
--------+-------------------+-----------+----------+----------+-----------
1 | example#gmail.com | Lin | Du | 123 | 1
(1 row)
node-sequelize-examples=# select * from "Chapter";
chapterId | chapterName | isChapterLocal
-----------+-------------+----------------
1 | ok | f
(1 row)

Excluding foreign key attributes causes nested queries to fail

On all my models I have a created by and updated by foreign key columns that link to my user model. When I query my database using findAll() for example, I always include them so that the user's username and other details are returned with my results - I also exclude the foreign key columns for the result at it makes no sense returning the created by object which includes the ID and and the createdById node as it's just duplicate data
"createdById": "21499bb6-4476-11e6-beb8-9e71128cae77",
"createdBy": {
"id": "21499bb6-4476-11e6-beb8-9e71128cae77",
"username": "mo.gusbi"
},
"updatedById": "21499bb6-4476-11e6-beb8-9e71128cae77",
"updatedBy": {
"id": "21499bb6-4476-11e6-beb8-9e71128cae77",
"username": "mo.gusbi"
}
So what I do is just exclude createdById and updatedById attributes and this works great, until I have to join other tables and include constraints (for pagination, that cause a subquery to be generated) which looks for the createdById and updatedById columns that I originally excluded, causing an SQL error
SequelizeDatabaseError: SQLITE_ERROR: no such column: Category.createdById
from the generated query
SELECT `Category`.*, `children`.`id` AS `children.id`,
`children`.`name` AS `children.name`,
`createdBy`.`id` AS `createdBy.id`,
`createdBy`.`username` AS `createdBy.username`,
`updatedBy`.`id` AS `updatedBy.id`,
`updatedBy`.`username` AS `updatedBy.username`,
`deletedBy`.`id` AS `deletedBy.id`,
`deletedBy`.`username` AS `deletedBy.username`
FROM (
SELECT `Category`.`id`,
`Category`.`name`,
`Category`.`parentId`
FROM `Categories` AS `Category`
WHERE (`Category`.`deletedAt` IS NULL
AND `Category`.`parentId` = NULL)
LIMIT 0, 10
) AS `Category`
LEFT OUTER JOIN `Categories` AS `children`
ON `Category`.`id` = `children`.`parentId`
AND `children`.`deletedAt` IS NULL
LEFT OUTER JOIN `Users` AS `createdBy`
ON `Category`.`createdById` = `createdBy`.`id`
AND `createdBy`.`deletedAt` IS NULL
LEFT OUTER JOIN `Users` AS `updatedBy`
ON `Category`.`updatedById` = `updatedBy`.`id`
AND `updatedBy`.`deletedAt` IS NULL
LEFT OUTER JOIN `Users` AS `deletedBy`
ON `Category`.`deletedById` = `deletedBy`.`id`
AND `deletedBy`.`deletedAt` IS NULL
;
Models
User = sequelize.define('User', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV1,
primaryKey: true
},
username: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
validate: {
notEmpty: true,
is: regex.username
}
}
}, {
paranoid: true,
classMethods: {
associate: (models) => {
User.belongsTo(models.User, {
foreignKey: 'createdById',
as: 'createdBy'
});
User.belongsTo(models.User, {
foreignKey: 'updatedById',
as: 'updatedBy'
});
User.belongsTo(models.User, {
foreignKey: 'deletedById',
as: 'deletedBy'
});
}
}
});
Category = sequelize.define('Category', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV1,
primaryKey: true
},
name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true
}
}
}, {
indexes: [{
unique: true,
fields: ['name', 'parentId']
}],
paranoid: true,
classMethods: {
associate: (models: any) => {
Category.belongsTo(models.User, {
foreignKey: 'createdById',
as: 'createdBy'
});
Category.belongsTo(models.User, {
foreignKey: 'updatedById',
as: 'updatedBy'
});
Category.belongsTo(models.User, {
foreignKey: 'deletedById',
as: 'deletedBy'
});
Category.belongsTo(models.Category, {
foreignKey: 'parentId',
as: 'parent'
});
Category.hasMany(models.Category, {
foreignKey: 'parentId',
as: 'children'
});
}
}
});
Query
Category
.findAll({
attributes: [
'id',
'name',
'parentId'
],
where: {
parentId: req.query.parentId
},
include: [
{
model: Category,
as: 'children',
attributes: [
'id',
'name'
]
},
{
model: User,
as: 'createdBy',
attributes: [
'id',
'username'
]
},
{
model: User,
as: 'updatedBy',
attributes: [
'id',
'username'
]
},
{
model: User,
as: 'deletedBy',
attributes: [
'id',
'username'
]
}
],
offset: 0,
limit: 10
});

Sequelize generates a not working SQL when use order option

when I use order option in #findAll it generates SQL:
SELECT
`id`, `first_name` AS `firstName`,
`last_name` AS `lastName` FROM `customers` AS `Customer`
ORDER BY `Customer`.`firstName` DESC;
but this SQL causes error:
ER_BAD_FIELD_ERROR: Unknown column 'Customer.firstName' in 'order clause'
Code example:
var Customer = sequelize.define("Customer", {
id: {
type: Sequelize.INTEGER({unsigned: true}),
primaryKey: true
},
firstName: {
type: Sequelize.STRING(32),
field: "first_name"
},
lastName: {
type: Sequelize.STRING(32),
field: "last_name"
}
}, {
name: {
singular: "customer",
plural: "customers"
},
tableName: "customers",
timestamps: false,
underscored: true
});
Customer.findAll({
order: [["firstName", "DESC"]]
}).then(function(list) {
console.log(list);
}).catch(function(err) {
console.log(err);
});
Mysql: 5.6.20
Sequelize: 3.14.2
Are there any solutions of this issue?
Use order: [["first_name", "DESC"]]; the ORDER BY looks at column names, not your SELECT alias firstName.