Sequelize Error : Column names in each table must be unique - node.js

I had an error in Sequelize with a foreign key not matching a column name. Checking the db, I saw that the column 'WokflowId' was named 'WorkflowID', so I changed the name in the Sequelize model.
It look like this
'use strict';
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const WorkflowsAccessRights = sequelize.define('Workflows_AccessRights', {
id:{
type: Sequelize.BIGINT,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
WorkflowID: Sequelize.BIGINT,
GroupID: Sequelize.BIGINT,
Enabled: Sequelize.INTEGER
},{
timestamps: false,
freezeTableName: true,
});
module.exports = WorkflowsAccessRights
But now that I changed the column name to get the right one, I get this error
Column names in each table must be unique. Column name 'WorkflowId' in table 'Workflows_AccessRights' is specified more than once.
Except that no column has this name now... Did I miss something in the setup or is there a way to freeze the column name?

Hope the following link will be helpful for you. It asks to put IF NOT EXISTS to the SQL script as follows,
IF NOT EXISTS(SELECT * FROM sys.columns WHERE Name = 'ColumnName'
AND object_id = OBJECT_ID('YourTableName'))
BEGIN
ALTER TABLE dbo.YourTableName
ADD ColumnName INT -- or whatever it is
END
Check this link. It is the same question that you have asked

So, after searching in the whole project. I found out that I was calling a foreignKey on WorkflowId. Therefore Sequelize tried to create a new column called WorkfklowId and had a bug doing it. I just renamed the foreignKey and it worked.

Related

Sequelize: how to let the database handle primary key value?

I'm using sequelize 6.5.0. I created a simple model to do two rudimentary things: a) find records, b) create records. I'm having trouble creating records; specifically, ones with primary key. If I designate the column as primaryKey like so:
const Table = sequelize.define('table', {
id: {
type: DataTypes.UUID,
primaryKey: true
},
datum: {...}
...
and try to create a record like so:
Table.create({datum: 'abc'})
then it will try (and fail) to set the primary key with:
INSERT INTO "table" ("id","datum") VALUES ($1,$2) RETURNING ...;
which is 50% what I did not ask it to do. Now, I don't need this to happen since default value for id is already handled at the database level. So, the next natural move was to not designate id as primaryKey:
const Table = sequelize.define('table', {
id: {
type: DataTypes.UUID,
// primaryKey: true
},
datum: {...}
...
But now sequelize attempts to get smart and throws a tantrum:
Uncaught Error: A column called 'id' was added to the attributes of 'table' but not marked with 'primaryKey: true'
Q) How do I get sequelize to NOT handle primary key on create?
I think you can skip the id field in the definition altogether, and PostgreSQL will still have one

Customizing sequelize-cli generated IDs

Created a model using:
sequelize-cli model:create --name User --attributes "dispName:string,email:string,phoneNum1:string,vendorId:integer"
Which resulted in the following migration:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
dispName: {
type: Sequelize.STRING
},
// plus others...
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users');
}
};
I want to change the automatically defined ID to:
cognitoId: {
allowNull: false,
primaryKey: true,
type: Sequelize.STRING(100)
}
So:
Will sequelize be able to recognize this as the ID?
Where all do I need to make this change? I could only identify the migration file.
The model file doesn't have a definition for the cognitoId (or the original auto-generated id field): how will I be able to get the value of a User instance's cognitoId (in the data returned by queries)?
Will changing the auto-generated id field have repercussions down the line?
Is the field name id "magical"? I.e., does the primary key have to be named id?
Is there a better way to do this?
Will changing the types of the fields from Sequelize.STRING to Sequelize.STRING(100) create any issues down the line?
Why doesn't the models file generated by sequelize-cli have the id field defined?
When generating models+migrations from the command-line I couldn't find any syntax to specify the ID or any other customization for the fields.
Using:
[Node: 12.14.1, CLI: 5.5.1, ORM: 5.21.3]
PS: relatively new to NodeJS & completely new to Sequelize.
Yes
You should declare custom named PK in your model
see p.2. If you don't declare PK in your model then sequelize assumes you have id PK with an integer type, autoincremented. If you wish to assign your PK another name you should declare it in the model.
Depends on what changes you make
It is the default PK name in sequelize (see p.3). You can set different name to your PK manually declaring it in your model (see p.3)
Personally I prefer to declare all PKs in my models even if they have id name and default PK type and value.
No issues if all PK values do not exceed this length
see p.3
You can define names and types only for fields while generating models from the command line.

Sequelize automatically adds colums

[Model].findOne({}) throws unknown colum error, but i dont have that column in my model, but it adds the colum modifieddate and updatedat and somecolum while fineOne runs
You have to add timestamp:false in the options where you are defining the model.
For example:
var Bar = sequelize.define('Bar', { }, {
timestamps: false,
})
For reference check this Sequelize model definition

Why does Sequelize add extra columns to SELECT query?

When i want to get some records with joined data from the referenced tables, Sequelize adds the reference columns twice: the normal one and a copy of them, written just a little bit different.
This is my model:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('result', {
id: {
type: DataTypes.INTEGER(10),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
test_id: {
type: DataTypes.INTEGER(10),
allowNull: false,
references: {
model: 'test',
key: 'id'
}
},
item_id: {
type: DataTypes.INTEGER(10),
allowNull: false,
references: {
model: 'item',
key: 'id'
}
},
}, // and many other fields
{
tableName: 'result',
timestamps: false, // disable the automatic adding of createdAt and updatedAt columns
underscored:true
});
}
In my repository I have a method, which gets the result with joined data. And I defined the following associations:
const Result = connection.import('../../models/storage/result');
const Item = connection.import('../../models/storage/item');
const Test = connection.import('../../models/storage/test');
Result.belongsTo(Test, {foreignKey: 'test_id'});
Test.hasOne(Result);
Result.belongsTo(Item, {foreignKey: 'item_id'});
Item.hasOne(Result);
// Defining includes for JOIN querys
var include = [{
model: Item,
attributes: ['id', 'header_en']
}, {
model: Test,
attributes: ['label']
}];
var getResult = function(id) {
return new Promise((resolve, reject) => { // pass result
Result.findOne({
where: { id : id },
include: include,
// attributes: ['id',
// 'test_id',
// 'item_id',
// 'result',
// 'validation'
// ]
}).then(result => {
resolve(result);
});
});
}
The function produces the following query:
SELECT `result`.`id`, `result`.`test_id`, `result`.`item_id`, `result`.`result`, `result`.`validation`, `result`.`testId`, `result`.`itemId`, `item`.`id` AS `item.id`, `item`.`title` AS `item.title`, `test`.`id` AS `test.id`, `test`.`label` AS `test.label` FROM `result` AS `result` LEFT OUTER JOIN `item` AS `item` ON `result`.`item_id` = `item`.`id` LEFT OUTER JOIN `test` AS `test` ON `result`.`test_id` = `test`.`id` WHERE `result`.`id` = '1';
Notice the extra itemId, testId it wants to select from the result table. I don't know where this happens. This produces:
Unhandled rejection SequelizeDatabaseError: Unknown column 'result.testId' in 'field list'
It only works when i specify which attributes to select.
EDIT: my tables in the database already have references to other tables with item_id and test_id. Is it then unnecessary to add the associations again in the application code like I do?
A result always has one item and test it belongs to.
How can i solve this?
Thanks in advance,
Mike
SOLUTION:
Result.belongsTo(Test, {foreignKey: 'test_id'});
// Test.hasMany(Result);
Result.belongsTo(Item, {foreignKey: 'item_id'});
// Item.hasOne(Result);
Commenting out the hasOne, hasMany lines did solve the problem. I think I messed it up by defining the association twice. :|
Sequelize uses these column name by adding an id to the model name by default. If you want to stop it, there is an option that you need to specify.
underscored: true
You can specify this property on application level and on model level.
Also, you can turn off the timestamps as well. You need to use the timestamp option.
timestamps: false
Although your solution fixes your immediate problem, it is ultimately not what you should be doing, as the cause of your problem is misunderstood there. For example, you MUST make that sort of association if making a Super Many-to-Many relationship (which was my problem that I was trying to solve when I found this thread). Fortunately, the Sequelize documentation addresses this under Aliases and custom key names.
Sequelize automatically aliases the foreign key unless you tell it specifically what to use, so test_id becomes testId, and item_id becomes itemId by default. Since those fields are not defined in your Result table, Sequelize assumes they exist when generating the insert set, and fails when the receiving table turns out not to have them! So your issue is less associating tables twice than it is that one association is assuming extra, non-existing fields.
I suspect a more complete solution for your issue would be the following:
Solution
Result.belongsTo(Test, {foreignKey: 'test_id'});
Test.hasMany(Result, {foreignKey: 'test_id'});
Result.belongsTo(Item, {foreignKey: 'item_id'});
Item.hasOne(Result, {foreignKey: 'item_id'});
A similar solution fixed my nearly identical problem with some M:N tables.

sequelize for Node.js : ER_NO_SUCH_TABLE

I'm new to sequelize and Node.js.
I coded for test sequelize, but error occured "ER_NO_SUCH_TABLE : Table 'db.node_tests' doesn't exist"
Error is very simple.
However, I want to get data from "node_test" table.
I think sequelize appends 's' character.
There is my source code.
var Sequelize = require('sequelize');
var sequelize = new Sequelize('db', 'user', 'pass');
var nodeTest = sequelize.define('node_test',
{ uid: Sequelize.INTEGER
, val: Sequelize.STRING} );
nodeTest.find({where:{uid:'1'}})
.success(function(tbl){
console.log(tbl);
});
I already create table "node_test", and inserted data using mysql client.
Does I misunderstood usage?
I found the answer my own question.
I appended Sequelize method option following. {define:{freezeTableName:true}}
Then sequelize not appends 's' character after table name.
Though the answer works nicely, I nowadays recommend the use of the tableName option when declaring the model:
sequelize.define('node_test', {
uid: Sequelize.INTEGER,
val: Sequelize.STRING
}, {
tableName: 'node_test'
});
http://docs.sequelizejs.com/manual/tutorial/models-definition.html
Sequelize is using by default the plural of the passed model name. So it will look for the table "node_tests" or "NodeTests". Also it can create the table for you if you want that.
nodeTest.sync().success(function() {
// here comes your find command.
})
Sync will try to create the table if it does not already exist. You can also drop the existing table and create a new one from scratch by using sync({ force: true }). Check the SQL commands on your command line for more details about what is going on.
When you define a model to an existing table, you need to set two options for sequelize to:
find your table name as-is and
not fret about sequelize's default columns updatedAt and createdAt that it expects.
Simply add both options like so:
var nodeTest = sequelize.define('node_test',
{ uid: Sequelize.INTEGER , val: Sequelize.STRING},
{ freezeTableName: true , timestamps: false} //add both options here
);
Note the options parameter:
sequelize.define('name_of_your_table',
{attributes_of_your_table_columns},
{options}
);
Missing either options triggers respective errors when using sequelize methods such as nodeTest.findAll().
> ER_NO_SUCH_TABLE //freezeTableName
> ER_BAD_FIELD_ERROR //timestamps
Alternatively, you can:
create a fresh table through sequelize. It will append "s" to the table name and create two timestamp columns as defaults or
use sequelize-auto, an awesome npm package to generate sequelize models from your existing database programmatically.
Here's the sequelize documentation for option configurations.
In my case, it was due to case. I was having:
sequelize.define('User', {
The correct way is to use lowercase:
sequelize.define('user', {

Resources