Primary key integer returning incremented on lookup - javascript

Edit: I have determined that this is only an issue when using Sequelize with SQLite. I had no problems after switching to Postgres. This question still stands though.
In Sequelize, I have Server and Seller models with a many-to-many relationship. The join model is IgnoredSellers.
const Server = sequelize.define('server', {
id: {
type: DataTypes.INTEGER,
primaryKey: true
}
}, { timestamps: false });
const Seller = sequelize.define('seller', {
id: {
type: DataTypes.STRING,
allowNull: false,
primaryKey: true
},
title: {
type: DataTypes.STRING,
allowNull: false
}
}, { timestamps: false });
const IgnoredSeller = sequelize.define('ignored_seller', {}, { timestamps: false });
Server.belongsToMany(Seller, { through: IgnoredSeller });
Seller.belongsToMany(Server, { through: IgnoredSeller });
Here's a sample row in the servers table:
id
84805370821310096
When I try Server.findByPk(84805370821310096), the returned Server instance has an id of 84805370821310100, which looks like an incremented version of the stored value.
const server = await Server.findByPk(serverId); // 84805370821310096 is passed in
// Executing (default): SELECT `id` FROM `servers` AS `server` WHERE `server`.`id` = '84805370821310096';
console.log('SERVER:', server.id); // 84805370821310100 is returned
So when I try server.addSeller(seller), I get a foreign key constraint error because the Server instance ID 84805370821310100 doesn't match any ID in the server table.
// Continued from above code
const seller = await Seller.findOne({ where: { title: sellerTitle }});
const ignoredSeller = await server.addSeller(seller);
// Executing (default): INSERT INTO `ignored_sellers` (`serverId`,`sellerId`) VALUES (84805370821310100,'amp');
// Failed to insert ignored seller: ForeignKeyConstraintError [SequelizeForeignKeyConstraintError]: SQLITE_CONSTRAINT: FOREIGN KEY constraint failed
What's causing this to happen?

You have to define IgnoredSeller like this -
const IgnoredSeller = sequelize.define(
"ignored_seller",
{
sellerId: Sequelize.INTEGER,
serverId: Sequelize.INTEGER,
},
{
timestamps: false
}
)

Related

Sequelize 6, delete cascade with M:N association

I'm trying to define some specific M:N association using sequelize v6.20.1 and i'm facing and issue...
I have 2 models, an Account model and a Group model.
My rules about these models are the following:
An account can exists without any group
An account can have multiple groups
A group can exists with a least one account associated, so that mean a group cannot exists without an account associated
A group can be associated with multiple accounts
Here is the code definition of all models and association :
const Sequelize, { Model, DataTypes } = require('sequelize');
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: `./database.sqlite`,
});
/* ----- Account model ----- */
class Account extends Model {
// Some account's methods definitions...
}
Account.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING,
username: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
}, { sequelize });
/* ----- Group model ----- */
class Group extends Model {
// Some group's methods definitions...
}
Group.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING,
}, { sequelize });
/* ----- AccountGroup model ----- */
class AccountGroup extends Model {
}
AccountGroup.init({
AccountId: {
type: DataTypes.INTEGER,
references: {
model: Account,
key: 'id',
},
onDelete: 'RESTRICT',
},
GroupId: {
type: DataTypes.INTEGER,
references: {
model: Group,
key: 'id',
},
allowNull: false,
onDelete: 'CASCADE',
},
}, {
sequelize,
timestamps: false,
});
/* ----- Association definition ----- */
Account.belongsToMany(Group, { through: AccountGroup });
Group.belongsToMany(Account, { through: AccountGroup });
sequelize.authenticate();
sequelize.sync({ force: true };
(async () => {
const group = new Group({ name: 'Group' });
await group.save();
const account = new Account({ name: 'Doe', username: 'John', email: 'john.doe#example.com', password: 'secret' });
account.addGroup(group);
await account.save();
// some processing code...
await account.destroy();
})();
After account.destroy() finished, the AccountGroup row is successfully deleted but not the Group. And i want to delete unreferenced groups.
What am i missing ?
This is the way that the cascading deletes works. In your example, when the Account is deleted, rows in the AccountGroup table may now have an invalid value in their AccountId foreign key column. You are telling the database that when this situation occurs, delete the AccountGroup entirely. Similarly, if you delete a Group, this will cascade down and delete any AccountGroup with that Group as its GroupId.
No such issue arises for the Account or Group tables when an AccountGroup is deleted. They do not contain any foreign keys that have been made invalid.
To find the functionality that you are searching for, deleting any groups that no longer belong to an AccountGroup, you will likely want to put a separate query in your code, or you may be able to use a Hook to be executed after an Account is deleted.

Why doesn't my backend update the keywordData column in database

My idea is to have the ability to add multiple strings at keyword, I've been told to use foreign keys and so am I. But I can't figure out why it's not working properly. Any ideas?
My code is as follows
user.js
var User = sequelize.define('user', {
username: Sequelize.STRING,
myhash: Sequelize.TEXT,
mysalt: Sequelize.STRING,
keyword: Sequelize.STRING
});
var keywordData = sequelize.define('keywordData', {
keywords: Sequelize.STRING
})
User.hasMany(keywordData)
keywordData.belongsTo(User)
User.js
router.post("/newkeyword", function(req, res) {
keywordData.update(
{keywordData: req.body.newkeyword},
{where: {id: req.user['id']}}
)
})
You forgot to indicate a foreignKey option in the second association definition as well as create an auto-increment id for keywordData model.
var keywordData = sequelize.define('keywordData', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true, },
keywords: { Sequelize.STRING }
})
Hence, your association should be like this:
User.hasMany(keywordData)
keywordData.belongsTo(User, {foreignKey: 'keyword', targetKey: 'keywords' })
Also you an refer this document for more details.

sequelize find data that is associated

I have 2 models Prophet and Task and they have a m:n relationship:
Prophets
const prophet = sequelize.define('prophets', {
name: {
type: Sequelize.STRING,
primaryKey: true,
unique: true
}
});
prophet.relationship = function(task) {
prophet.belongsToMany(task, {
through: 'prophetTasks',
as: 'tasks',
foreignKey: 'prophetName'
});
};
Tasks
const task = sequelize.define('tasks', {
name: {
type: Sequelize.STRING,
primaryKey: true,
unique: true
}
});
task.relationship = function(prophet) {
task.belongsToMany(prophet, {
through: 'prophetTasks',
as: 'prophets',
foreignKey: 'taskName'
});
};
EDITED:
my problem is sometimes I have to update a prophet which might remove some relationships with tasks, but I cant figure out how to delete the tasks that have no more relationship with any prophets.
I believe I should find all tasks that doesnt belong in prophetTasks table anymore, but I dont know how to query that with sequelize
You can use ON DELETE CASCADE
So whenever the row is deleted, data containing it as a foreign key will be deleted.

Sequelize Populate Relation Query Either Table

I have the following two tables in Sequelize
const Tokens = sequelize.define("Tokens", {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
active: {
type: DataTypes.BOOLEAN
}
});
and
const User = sequelize.define("Users", {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
first_name: {
type: DataTypes.STRING
}
});
User.associate = models => {
models["Users"].hasMany(models["Tokens"], {foreignKey: 'userID', as: 'tokens_userid'});
};
I'm trying to run the following query in Sequelize.
const token = await db.Tokens.findOne({
where: {
id,
active: true
},
include: ["tokens_userid"]
});
But I'm getting the following error.
Error: Association with alias "tokens_userid" does not exists
My main goal is to get the user based on a Token ID. Now I would just move that association to the User table, but the problem with that later on I will want to get all the tokens for a given User ID. So I will run into this problem either way.
I tried adding the following line, but it was complaining about circular relations or something like that.
models["Tokens"].hasOne(models["User"], {foreignKey: 'userID', as: 'tokens_userid'});
How can I query either the Users or Tokens table and have it populate correctly with the relation?
I was able to solve this by adding the following line to my table.
models["Tokens"].belongsTo(models["User"], {foreignKey: 'userID', as: 'tokens_userid_from_token'});
Basically what I tried before but changed hasOne to belongsTo.
Hopefully this helps someone else.

In NodeJS, is there a method similar to dependant: :destroy in Ruby for associated records?

I’m trying to delete tasks when delete a associated farmer. I have read a sequelize docs and i have done the same solutions in there. But i can not delete tasks automatically. Also I have tried solutions in the following links:
Sequelize onDelete not working
Sequelize.js onDelete: 'cascade' is not deleting records sequelize
I'm using sequelizejs with mysql.
My models:
Task.js
'use strict';
var Farmer = require('./farmer');
module.exports = function(sequelize, DataTypes) {
var Task = sequelize.define('Task', {
title: DataTypes.STRING,
deadline: DataTypes.DATE,
description: DataTypes.TEXT,
FarmerId: {
type: DataTypes.INTEGER,
references: {
// This is a reference to another model
model: Farmer,
// This is the column name of the referenced model
key: 'id'
}
}
}, {
classMethods: {
associate: function(models) {
Task.belongsTo(models.Farmer, {foreignKey: 'FarmerId'});
// associations can be defined here
}
}
});
return Task;
};
Farmer.js
'use strict';
var validator = require('validator');
module.exports = function(sequelize, DataTypes) {
var Farmer = sequelize.define('Farmer', {
username:{
type: DataTypes.STRING,
allowNull: false,
},
address: DataTypes.STRING,
email: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
validate: {
isEmail: { args: true, msg: "not a valid email!" },
len: { args: [0, 100], msg: "email can't be bigger than 100"},
}
},
phone:{
type: DataTypes.STRING,
allowNull: false,
},
}, {
classMethods: {
associate: function(models) {
Farmer.hasMany(models.Task, {onDelete: 'CASCADE', hooks:true});
// associations can be defined here
}
}
});
return Farmer;
};
What else can I do?
Also, Do I need to set ‘on delete cascade’ on mysql related table? If I don’t do it, sequelize define association onDelete doesnt work?
You can omit FarmerId in your definition of Task. Sequelize automatically knows that there's a FarmerId by associating Task with Farmer. Try that, everything else seems very usual.

Categories