Related
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.
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
/* 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. But the primary Key auto-increment is still continuing
http://localhost:4000/api/v1/post : 2022-08-28T11:02:47+03:00
Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): START TRANSACTION;
Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9): INSERT INTO posts
(id,title,text,username,createdAt,updatedAt) VALUES
(DEFAULT,?,?,?,?,?); Executing (ac12d76f-d7dc-4040-9692-3d6b853feac9):
ROLLBACK;
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. But this issue does not exist if using Object.findOrCreate() with following mentioned versions.
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() e.g 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.
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
Versions: "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;
I have a fetch API to get values from mysql database.Below is my screen code in which I need to get data from API:
TargetSetUpPage.js:
import React, {
useState,
useEffect,
useReducer,
useSelector,
Component,
} from "react";
import { StyleSheet, Text, Button, TextInput, ScrollView } from "react-native";
import * as authActions from "../../store/actions/auth";
const TargetSetUpPage = (props) => {
const [targetid, setTargetId] = React.useState("");
const onScreenLoad = () => {
let action;
action = authActions.getDeviceInfo();
};
useEffect(() => {
onScreenLoad();
});
return (
<ScrollView showsVerticalScrollIndicator={true}>
<Text style={styles.headingTitle}>
Set your target and start running:
</Text>
<Text style={styles.textstyle}>Target ID</Text>
<TextInput
style={styles.input}
value={targetid}
onChangeText={(targetid) => setTargetId(targetid)}
></TextInput>
<Button
title="Add"
// onPress = {() => }
/>
</ScrollView>
);
};
const styles = StyleSheet.create({
input: {
height: 40,
width: "80%",
margin: 12,
borderWidth: 1,
padding: 10,
},
headingTitle: {
fontSize: 30,
},
textstyle: {
paddingTop: 10,
fontSize: 20,
},
compact: {
flexDirection: "row",
},
buttonleft: {
paddingTop: 40,
height: 40,
width: "80%",
},
});
export default TargetSetUpPage;
Below is the store code which calls fetch API.
auth.js
import AsyncStorage from "#react-native-community/async-storage";
import Device from "../../model/Device";
export const LOGIN = "LOGIN";
export const LOGOUT = "LOGOUT";
export const GETDEVICEINFO = "GETDEVICEINFO";
export const login = (textemailid, textpassword) => {
const formData = new FormData();
formData.append("txtUemail", textemailid);
formData.append("txtUpass", textpassword);
return async (dispatch) => {
fetch("https://------------------------/login.php", {
method: "post",
body: formData,
})
.then((res) => res.text())
.then((loginresult) => {})
.catch((err) => {
console.log(err);
});
const saveDataToStorage = (loginresult) => {
AsyncStorage.setItem(
"userData",
JSON.stringify({
loginresult: loginresult,
})
);
};
dispatch({ type: LOGIN });
};
};
export const logout = () => {
return { type: LOGOUT };
};
export const getUserInfo = (textemailid) => {
const formData = new FormData();
formData.append("txtEmail", textemailid);
return async (dispatch) => {
fetch("https://------------------------/getUserInformation.php", {
method: "post",
body: formData,
})
.then((res) => res.json())
.then((getuseridresult) => {
const userid = getuseridresult.map((d) => d.id);
saveDataToStorage(userid);
})
.catch((err) => {
console.log(err);
});
const saveDataToStorage = async (userid) => {
try {
await AsyncStorage.setItem(
"userDatauserid",
JSON.stringify({
userid: userid,
})
);
} catch (e) {
alert("not saved");
}
};
};
};
export const getDeviceInfo = async () => {
const useridfordevices = await AsyncStorage.getItem("userDatauserid");
const obj = JSON.parse(useridfordevices);
const { userid } = obj;
var userid1 = userid[0];
console.log("txtUserId is " + userid1);
const formData = new FormData();
formData.append("txtUserId", userid1);
console.log(formData);
return async (dispatch) => {
fetch("https://-------------------------------/getDeviceInformation.php", {
method: "post",
body: formData,
})
.then((res) => res.json())
.then((result) => {
console.log("Hi" + result);
})
.catch((err) => {
console.log(err);
});
};
};
getDeviceInfo function in the above auth.js is not returning anything. I am sending correct data to fetch API as below:
txtUserId is 616718042ad26
FormData {
"_parts": Array [
Array [
"txtUserId",
"616718042ad26",
],
],
In postman I am getting the below JSON data:
[
{
"targetid": "TargetDevice1",
"targetname": "device_1",
"userid": "616718042ad26"
},
{
"targetid": "TargetDevice2",
"targetname": "device_2",
"userid": "616718042ad26"
}
]
Import and add dispatch in TargetSetUpPage:
TargetSetUpPage.js:
import React, {
useState,
useEffect,
useReducer,
useSelector,
Component,
} from "react";
import { StyleSheet, Text, Button, TextInput, ScrollView } from "react-
native";
import { useDispatch } from "react-redux";
import * as authActions from "../../store/actions/auth";
import AsyncStorage from '#react-native-community/async-storage';
const TargetSetUpPage = (props) => {
const [targetid, setTargetId] = React.useState("");
const dispatch = useDispatch();
const onScreenLoad = async() => {
const useridfordevices = await AsyncStorage.getItem("userDatauserid");
const obj = JSON.parse(useridfordevices);
const { userid } = obj;
var userid1 = userid[0];
console.log("txtUserId is " + userid1);
let action;
action = authActions.getDeviceInfo(
userid1
);
await dispatch(action);
};
useEffect(() => {
onScreenLoad();
});
return (
<ScrollView showsVerticalScrollIndicator={true}>
<Text style={styles.headingTitle}>
Set your target and start running:
</Text>
<Text style={styles.textstyle}>Target ID</Text>
<TextInput
style={styles.input}
value={targetid}
onChangeText={(targetid) => setTargetId(targetid)}
></TextInput>
<Button
title="Add"
// onPress = {() => }
/>
</ScrollView>
);
};
const styles = StyleSheet.create({
input: {
height: 40,
width: "80%",
margin: 12,
borderWidth: 1,
padding: 10,
},
headingTitle: {
fontSize: 30,
},
textstyle: {
paddingTop: 10,
fontSize: 20,
},
compact: {
flexDirection: "row",
},
buttonleft: {
paddingTop: 40,
height: 40,
width: "80%",
},
});
export default TargetSetUpPage;
In the store, dispatch the action to TargetSetUpPage.js from getDeviceInfo function.
auth.js:
export const getDeviceInfo = (userid1) => {
const formData = new FormData();
formData.append("txtUserId", userid1);
return async dispatch => {
fetch('https://----------/getDeviceInformation.php',
{
method:'post',
body: formData
})
.then((res) => res.json())
.then((getuserdeviceinfo) => {
const loadDevices = [];
loadDevices.push(
new Device(
getuserdeviceinfo.map((d) => d.targetid),
getuserdeviceinfo.map((d) => d.targetname),
)
);
console.log(loadDevices);
})
.catch((err) =>{
console.log(err);
})
dispatch({type:GETDEVICEINFO,availableDevice:loadDevices})
}
}
This displays the Device array from mysql database.
Array [
Device {
"TargetId": Array [
"jtgTargetDevice1",
"jtgTargetDevice2",
],
"TargetName": Array [
"device_1",
"device_2",
],
},
]
I'm building an API using nodejs, sequelize, dan MySQL database (10.1.21-MariaDB). When I tried to do some PATCHing (updating data), it throws AssertionErrors, but it works fine with POST (inserting data).
Here's my patch code:
const express = require('express');
const router = express.Router();
const brandModel = sequelize.define('tbl_brand', {
brand_name: {
type: Sequelize.STRING,
allowNull: false
},
}, {
freezeTableName: true,
});
router.patch('/:id', (req, res, next) => {
const id = req.params.id;
const newModel = {
brand_name: req.body.brand_name
};
sequelize.authenticate().then(() => {
const promise = brandModel.update(newModel, {brand_id: id});
return promise.then(function(item){
res.status(201).json({
success: true,
result: item
});
});
})
.catch(err => {
res.status(500).json({
success: false,
result: err
});
});
});
I use postman and access it like this:
http://localhost:3000/brand/1
With Raw JSON:
{
"brand_name" : "Adidasssss"
}
And here's the result:
{
"success": false,
"result": {
"generatedMessage": false,
"name": "AssertionError [ERR_ASSERTION]",
"code": "ERR_ASSERTION",
"expected": true,
"operator": "=="
}
}
What could be the problem?
Nevermind... I was careless, I was updating an empty instance called brandModel. It should be searched first then do the update
Template.users.rendered = function () {
Template.instance().subscribe('userList');
if (Session.get('apply_tablestyling')==1) {
console.log('in datatable');
$('#users').dataTable({
"paging": true,
"lengthChange": false,
"searching": true,
"ordering": true,
"info": true,
"autoWidth": false
});
}
}
I am using datatables-bootstrap-3, I need to add export buttons. Everything is working except showing the export buttons.
have you tried adding buttons to your initialization?
buttons: ['copy', 'csv', 'excel', 'pdf', 'print']
dom: 'Bfrtip',
buttons: [
{
text: 'Export to JSON',
action: function ( e, dt, node, config ) {
var data = dt.buttons.exportData();
$.fn.dataTable.fileSave(
new Blob( [ beautify(data , null, 2, 100) ] ),
'Families_'+ Date.now() +'.json'
);
}
}
,{
text: 'Export to CSV',
action: function ( e, dt, node, config ) {
var data = dt.buttons.exportData();
$.fn.dataTable.fileSave(
new Blob( [json2csv({ data: data.body, fields: null })]),
'Families_'+ Date.now() +'.csv'
);
}
}
]
then in both routes.js :
Router.route('/users', {
name: 'users',
action: function() {
var self = this;
$.getScript('https://cdn.datatables.net/buttons/1.2.4/js/dataTables.buttons.min.js', function(data, textStatus, jqxhr) {
if(jqxhr.status === 200) {
//self.render();
$.getScript('https://cdn.datatables.net/buttons/1.2.4/js/buttons.html5.min.js', function(data, textStatus, jqxhr) {
if(jqxhr.status === 200) {
self.render();
}
});
}
});
}
});
I am calling a rest webscript using Extjs with JSON,but unable to display on view.
The problem is i am getting the json data as response from the server.But when i want to display on view.Its not getting displayed.
here is my json:
{
"data":
{
"ticket":"TICKET_87c91dd9d18d7242e44ff638df01e0cb388ee4c7"
}
}
and here is extjs code:
Ext.onReady(function() {
alert("in login js");
var store = new Ext.data.JsonStore({
proxy : new Ext.data.ScriptTagProxy({
// url : 'http://ip:8080/alfresco/service/api/login',
url : 'http://ip:8080/alfresco/service/api/login?u=Value1&pw=Value2&format=json',
method : 'GET'
}),
reader : new Ext.data.JsonReader({
root : 'data',
fields : ['ticket']
})
});
alert("after the webscript call");
//store.load();
var grid = new Ext.grid.GridPanel({
renderTo: 'PagingFragment',
frame:true,
width:600,
height:800,
autoHeight: true,
autoWidth: true,
store: store,
loadMask:true,
columns: [
{
height:100,
width:100,
header: "Ticket",
dataIndex: 'ticket',
// renderer: title_img,
//id: 'ticket',
sortable: true
}
],
bbar: new Ext.PagingToolbar({
pageSize: 2,
store:store,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}'
}),
sm: new Ext.grid.RowSelectionModel({
singleSelect: true,
listeners: {
rowselect: {
fn: function(sm,index,record) {
Ext.Msg.alert('You Selected',record.data.title);
}
}
}
})
});
store.load({
params: {
start: 0,
limit: 5
}
});
});
and in jsp:
<body>
<div id="PagingFragment" style="position:absolute;top:10px;left:200px">
</div>
</body>
could anybody help on this
'data' must be an array.
Instead of { data: { ticket: 'blahblahblah' } } you must return
{ data: [{ ticket: 'blahblahblah' }] } see the diference?