[英]How do I skip the primary key auto increment in sequelize node js when unique constraint error occurs
How do I skip the primary key auto increment in sequelize node.js when unique constraint error occurs When I enter same username twice that was defined as unique into mysql by using of Postman my program is running correct way but the problem is the incremental primary key is still continuing.当发生唯一约束错误时,如何在 sequelize node.js 中跳过主键自动递增当我使用 Postman 输入两次被定义为唯一的相同用户名时,我的程序运行正确,但问题是增量主键仍然是继续。 For example when I insert another different username value the program is jumping at one of the sequential primary key as expected.
例如,当我插入另一个不同的用户名值时,程序会按预期跳转到顺序主键之一。 So that, How can I stop the auto increment id as I restricted not to insert duplicate username values in my database
因此,我如何停止自动递增 id,因为我限制不在我的数据库中插入重复的用户名值
/* DATABASE CONFIGURATION FILE */
const { Sequelize, QueryTypes, DataTypes, Op, UniqueConstraintError, ValidationErrorItem } = require(`sequelize`);
const sequelize = new Sequelize(`tutorialdb`, `root`, ``, {
host: `localhost`,
dialect: `mysql`,
logging: true,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000,
},
});
sequelize
.authenticate()
.then(() => {
console.log(`Connection has been established successfully...`);
})
.catch((err) => {
console.log(`Unable to connect to the database: `, err);
});
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.QueryTypes = QueryTypes;
db.DataTypes = DataTypes;
db.Op = Op;
db.ValidationErrorItem = ValidationErrorItem;
db.UniqueConstraintError = UniqueConstraintError;
db.postModel = require(`../models/post.model.jsx`)(sequelize, DataTypes);
db.sequelize.sync({ force: false, alter: false, match: /tutorialdb$/ }).then(() => {
console.log(`Tables were synced successfully`);
});
module.exports = db;
/* Model definition File */
module.exports = (sequelize, DataTypes) => {
const Post = sequelize.define(
`post`,
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
title: {
type: DataTypes.STRING(30),
allowNull: false,
validate: {
notEmpty: {
args: true,
msg: `Title is required`,
},
len: {
args: [3, 50],
msg: `Title must between 3 and 30 characters`,
},
},
},
text: {
type: DataTypes.STRING(100),
allowNull: false,
validate: {
notEmpty: {
args: true,
msg: `Text is required`,
},
len: {
args: [5, 100],
msg: `Text must between 5 and 100 characters`,
},
},
},
username: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
validate: {
notEmpty: {
args: true,
msg: `Username is required`,
},
len: {
args: [3, 20],
msg: `Username must between 3 and 20 characters`,
},
},
},
},
{
timestamps: true,
paranoid: true,
}
);
Post.beforeCreate(async (post, options) => {
post.username = post.username.toLowerCase();
});
Post.beforeUpdate(async (post, options) => {
post.username = post.username.toLowerCase();
});
return Post;
};
/* Controller File */
const db = require(`../config/db.config.jsx`);
const postModel = db.postModel;
const Sequelize = db.Sequelize;
const sequelize = db.sequelize;
const QueryTypes = db.QueryTypes;
const DataTypes = db.DataTypes;
const Op = db.Op;
const ValidationErrorItem = db.ValidationErrorItem;
const UniqueConstraintError = db.UniqueConstraintError;
/* Create new Post */
exports.create = async (req, res) => {
const transactions = await sequelize.transaction();
try {
const trim = (noSpace) => {
return noSpace.replace(/\s/g, ``);
};
const post = await postModel.create(
{
title: req.body.title,
text: req.body.text,
username: trim(req.body.username),
},
{ transaction: transactions }
);
await transactions.commit();
res.status(200).json(post);
} catch (err) {
await transactions.rollback();
const messages = {};
let message;
err.errors.forEach((error) => {
messages[error.path] = error.message;
message = messages[error.path];
});
res.status(500).json(message);
}
};
/* Find All posts */
exports.findAll = async (req, res) => {
const transactions = await sequelize.transaction();
try {
const title = req.query.title;
const text = req.query.text;
const username = req.query.username;
let finder = title ? { title: { [Op.like]: `%${title}%` } } : text ? { text: { [Op.like]: `%${text}%` } } : username ? { username: { [Op.like]: `%${username}%` } } : null;
const posts = await postModel.findAll({
as: `posts`,
attributes: [`id`, `title`, `text`, `username`, `createdAt`, `updatedAt`, `deletedAt`],
transaction: transactions,
lock: false,
paranoid: false,
order: [[`id`, `DESC`]],
where: finder,
});
await transactions.commit();
res.status(200).json(posts);
} catch (err) {
await transactions.rollback();
res.status(500).json(err.message);
}
};
/* Router File */
module.exports = (app) => {
const router = require(`express`).Router();
const postCtrl = require(`../controllers/post.controller.jsx`);
router.route(`/post`).post(postCtrl.create).get(postCtrl.findAll);
app.use(`/api/v1`, router);
};
/* MiddleWare Logger File */
const moment = require(`moment`);
/* Create Logger */
const logger = (req, res, next) => {
console.log(`${req.protocol}://${req.get(`host`)}${req.originalUrl} : ${moment().format()}`);
next();
};
module.exports = logger;
/* Server File */
const express = require(`express`);
const cors = require(`cors`);
const logger = require(`./src/middleware/logger.jsx`);
const app = express();
const corsOptions = {
origin: `http://localhost:4001`,
optionsSuccessStatus: 200,
};
app
.use(cors(corsOptions))
.use(logger)
.use(express.json())
.use(express.urlencoded({ extended: false }))
.get(`/`, (req, res) => res.status(200).send(`Welcome to fullstack tutorial application`));
require(`./src/routes/routers.jsx`)(app);
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => console.log(`Server is running on port ${PORT}...`));
The output result is working well. output 结果运行良好。 But the primary Key auto-increment is still continuing
但是primary Key自增还在继续
http://localhost:4000/api/v1/post: 2022-08-28T11:02:47+03:00 Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): START TRANSACTION;
http://localhost:4000/api/v1/post: 2022-08-28T11:02:47+03:00 执行 (ac12d76f-d7dc-4040-9692-3d6b853feac9): 开始交易; Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): INSERT INTO
posts
(id
,title
,text
,username
,createdAt
,updatedAt
) VALUES (DEFAULT,?,?,?,?,?);执行(ac12d76f-d7dc-4040-9692-3d6b853feac9):插入
posts
(id
,title
,text
,username
,createdAt
,updatedAt
)VALUES(默认,?,?,?,?,?); Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): ROLLBACK;执行(ac12d76f-d7dc-4040-9692-3d6b853feac9):回滚;
I had attempted the following solution and works me perfectly.我尝试了以下解决方案并完美地工作。
/* Create new User */
exports.create = async (req, res) => {
const trim = (noSpace) => {
return noSpace.replace(/\s/g, ``);
};
const transactions = await sequelize.transaction();
try {
const { username, password } = req.body;
const users = await userModel.findOne({
where: { username: trim(username) },
transaction: transactions,
});
if (users !== null) {
await transactions.rollback();
res.json(`Username ${username} already exist`);
} else {
const user = await userModel.create(
{
username: trim(username),
password: trim(password),
},
{
transaction: transactions,
}
);
await transactions.commit();
res.status(200).json(user);
}
} catch (err) {
await transactions.rollback();
const messages = {};
let message;
err.errors.forEach((error) => {
messages[error.path] = error.message;
message = messages[error.path];
});
res.status(500).json(message);
}
};
exports.create = async (req, res) => {
const transactions = await sequelize.transaction();
try {
const trim = (noSpace) => {
return noSpace.replace(/\s/g, ``);
};
const [user, created] = await userModel.findOrCreate({
where: { username: trim(req.body.username) },
defaults: { password: trim(req.body.password) },
transaction: transactions,
});
return created ? (await transactions.commit(), res.status(200).json(user)) : user ? (await transactions.rollback(), res.json(`Username already exist`)) : err;
} catch (err) {
await transactions.rollback();
const messages = {};
let message;
err.errors.forEach((error) => {
messages[error.path] = error.message;
message = messages[error.path];
});
res.status(500).json(message);
}
};
I am not sure about issue's existence in previous versions of sequelize.我不确定以前版本的 sequelize 中是否存在问题。 But this issue does not exist if using Object.findOrCreate() with following mentioned versions.
但是,如果将 Object.findOrCreate() 与以下提到的版本一起使用,则不存在此问题。
However this issue does appear if using Object.create() method with unique constraint set for field value and not checking field value existence prior to using Object.create() eg in following code email unique property is set and if user.create() is used for an existing email in db an error is thrown but userid is incremented thus for next successful creation userid is not as expected.但是,如果使用 Object.create() 方法并为字段值设置了唯一约束,并且在使用 Object.create() 之前不检查字段值是否存在,例如在以下代码中设置了 email 唯一属性,并且如果 user.create()用于数据库中现有的 email 会抛出错误,但 userid 会递增,因此对于下一次成功创建,userid 与预期不同。
An alternate solution is using user.findOne() prior to use user.create() but out of the scope of this answer and issue can be avoided using object.findOrCreate() as following另一种解决方案是在使用 user.create() 之前使用 user.findOne() 但在这个答案的 scope 之外,可以使用 object.findOrCreate() 避免问题,如下所示
Versions: "mysql2": "^2.3.3", "sequelize": "^6.28.0"版本:“mysql2”:“^2.3.3”,“sequelize”:“^6.28.0”
To avoid the issue try using following approach为避免此问题,请尝试使用以下方法
const router = require("express").Router();
const { Sequelize, DataTypes, Model } = require("sequelize");
const dotenv = require("dotenv");
dotenv.config();
const sequelize = new Sequelize(
process.env.MYSQL_DB_NAME,
process.env.MYSQL_DB_USER,
process.env.MYSQL_DB_PASS,
{
host: process.env.MYSQL_DB_HOST,
dialect: "mysql",
}
);
class User extends Model {}
User.init(
{
userid: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
field: "fUserID",
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
field: "fEmail",
},
password: {
type: DataTypes.STRING(1024),
allowNull: false,
field: "fPassword",
},
firstname: {
type: DataTypes.STRING,
field: "fFirstName",
},
lastname: {
type: DataTypes.STRING,
field: "fLastName",
},
metadata: {
type: DataTypes.STRING(2048),
field: "fMetaData",
},
created: {
type: DataTypes.DATE,
field: "fCreated",
},
updated: {
type: DataTypes.DATE,
field: "fUpdated",
},
},
{
sequelize,
tableName: "tbl_user",
timestamps: true,
id: "userid",
createdAt: "created",
updatedAt: "updated",
}
);
router.post("/register", async (req, res) => {
try {
const [user, created] = await User.findOrCreate({
where: { email: req.body.email },
defaults: {
password: req.body.password,
firstname: req.body.firstname,
lastname: req.body.lastname,
metadata: "Any thing",
},
});
if (created === false) return res.status(400).send("email already exist");
res.send(user.toJSON());
} catch (ex) {
res.status(400).send(ex.errors[0].message);
}
});
module.exports = router;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.