I am getting a SequelizeDatabaseError Data truncated for column 'position' at row 4 while sending an update request as below: Any advise on how to fix the database error ?
Executing (default): UPDATE user SET photo=?,name=?,email=?,phonenumber=?,position=?,password=?,updatedAt=? WHERE email = ?
SequelizeDatabaseError: Data truncated for column 'position' at row 4
at Query.formatError (C:\Project\soccerpep\node_modules\sequelize\lib\dialects\mysql\query.js:244:16)
at Execute.handler [as onResult] (C:\Project\soccerpep\node_modules\sequelize\lib\dialects\mysql\query.js:51:23)
module.exports = function(sequelize, DataTypes) {
return sequelize.define('user', {
name: {
type: DataTypes.STRING(30),
allowNull: false
},
email: {
type: DataTypes.STRING(100),
allowNull: false
},
phonenumber: {
type: DataTypes.STRING(50),
},
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
password: {
type: DataTypes.STRING(50),
allowNull: false
},
privilege: {
type: DataTypes.ENUM('PLAYER','ADMIN'),
},
photo: {
type: DataTypes.STRING(30),
},
position: {
type: DataTypes.ENUM('FORWARD','MID-FIELD','DEFENDER','GK'),
}
}, {
tableName: 'user'
});
};
server.js
const UserModel = userSchema(sequelize, DataTypes);
app.put('/service/profile', async (req, res, next) => {
try {
const userEmail = req.query.email;
var selector = {
where: { email: userEmail }
};
const updatePlayer = await UserModel.update(req.body, selector);
console.log("Server side update method log:" + updatePlayer);
res.status(200).json({ success: true });
} catch (err) {
return next(err);
}
});
I think the issue is with ENUM, you can use that only with Postgres and not with mysql , ( Ref )
position: {
type: DataTypes.ENUM('FORWARD','MID-FIELD','DEFENDER','GK'),
}
Change it to simple string type and check again,
position: {
type: DataTypes.STRING(30)
}
NOTE : You might need to create table again or update the field
manually after changing this in model else you will still get the
error
If you want to use ENUMs in mysql you should use it as so
position: {
type: DataTypes.ENUM,
values: ['player', 'admin],
defaultValue: 'monthly' // A default value just incase you fail to provide one...
},
I do hope this helps...
Change datatype is not the solution. You have to check the data that you try to save. eg: if ENUM("0", "1") and you try to saved data 0 then it's showing that type of error. You have to save like that "0". Then it's not showing such type of error message again.
i have a lot spending my day to tracing this error.
i have following all solution but doesnt work.
in my case and my bad is...
i forgot have clone table/duplicate/history/trigger that save old and new data.
make sure your history table have same data type.
i have table like these
form3
hs_form3 // its mean history with revision (number of revisi data) column and action column (create/update/delete/any)
just for description
CREATE TABLE hs_form3 LIKE form3;
ALTER TABLE hs_form3 MODIFY COLUMN id int(11) NOT NULL,
DROP PRIMARY KEY, ENGINE = InnoDB, ADD action VARCHAR(8) DEFAULT 'insert' FIRST,
ADD revision INT(6) NOT NULL AUTO_INCREMENT AFTER action,
ADD dt_datetime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER revision,
ADD PRIMARY KEY (revision),
ADD KEY `user_id` (`user_id`),
and i didnt run migration on server because a lot of change , i only run on localhost. in server i just put a new table by export import or added manual. before i got issue about migration on server and doesnt capture last change in sql table and dont have time to resolve.
Related
I'm a student working on a chat application for my internship, where I use socket.io.
Right now I am busy thinking of a good way to store the messages send in conversations.
As of now I do the following:
For each conversation between one user and another user, a new collection is made.
On every message sent, the message is stored in the according conversation collection in a single document.
The collections:
Where the document looks as follows:
Now I wonder if there is a good argument to be made to have just one collection "conversations", and store all the messages in multiple documents, where each conversation is a new document.
Creating a new collection for every message is very bad idea instead of that you use a simple schema as given below to store your messages
const conversation_schema = new Schema({
from: {
type: ObjectID,
ref: 'User'
},
to: {
type: ObjectID,
ref: 'User'
},
messageBody: { // body of the message(text body/ image blob/ video blob)
type: String,
},
messageType: { // type of the message(text, mp3, mp4, etc...)
type: String,
},
read: { // to boolean flag to mark whether the to user has read the message
type: Boolean,
default: false,
},
createdAt: { // when was this message goit created
type: Date,
default: new Date(),
},
});
you can fetch the conversation between the two users using the following query
conversations.find({
$or: [
{from: 'user1', TO: 'user2},
{from: 'user2', TO: 'user1},
],
}).populate({ path: 'to', model: User })
.populate({ path: 'from', model: User })
.sort({ createdAt: -1 })
Mongoose/MongoDB Question
I have an Owners model containing basic profile data.
I have a secondary model: OwnersImages
e.g
{
owner: {
type: Schema.Types.ObjectId,
ref: 'Owners'
},
name: String,
imageUrl: String,
},
);
From the client I want to post the imageUrl and the name to the OwnersImages table.
e.g
let values = {
owner: this.state.user._id,
name: this.state.field,
imageUrl: this.state.url
}
axios.post(`${serverPath}/api/addFieldImage`, values)
However Im unsure how best to go about this, link it etc.
I can do a GET request on the Owners table to get the Owner data, but then posting this as part of the values to OwnerImages doesn't successfully link the two tables.
Do i need to just store a string reference to the Owner id in OwnerImages or is there a smarter way of doing this?
Or should I just post the string of the user Id to mongoose and then do a map to the Owner table from within there?
Tried to explain this best way I could but the eyes are tired so please ask if any confusion!
Many thanks
Without seeing your exact setup, I think you could modify this to fit your needs:
// In the Schema/Model files
const ownersSchema = Schema({
// other fields above...
images: [{ type: Schema.Types.ObjectId, ref: 'OwnersImages' }]
});
const ownersImagesSchema = Schema({
// other fields above...
owner: { type: Schema.Types.ObjectId, ref: 'Owners' },
});
// in the route-handler
Owners.findById(req.body.owner, async (err, owner) => {
const ownersImage = new OwnersImages(req.body);
owner.images.push(ownersImage._id);
await ownersImage.save();
await owner.save();
});
As a side-note, I think the Models generally have singular names, so Owner and OwnerImage. The collection will then automatically take on the plural form. Just food for thought.
When you want to load these, you can link them with populate(). Consider loading all of the OwnersImages associated with an Owners in some route-handler where the /:id param is the Owners id:
Owners
.findOne({ _id: req.params.id })
.populate('images')
.exec(function (err, images) {
if (err) return handleError(err);
// do something with the images...
});
I'm using react-native-gifted-chat in my react-native app. As I shown in this image, there is same message displayed multiple time and message: Yes getting new msg 's place is also varied from it's actual position.
My issue is same as this. Can anyone please help me to solve this.
Thank you in advance.
I got a solution of my question. #Ron you are right but in my case the issue is different. I solved it by change my format of parameters. It took different format and I passed different so they conflicted each other. Here is the solution it may useful to others.
parse = snapshot => {
const { timestamp: numberStamp, text } = snapshot.val();
const { key: _id } = snapshot;
const createdAt = moment(snapshot.val().createdAt, "DD/MM/YYYY hh:mm:ss");
const user = { };
var temp_data = snapshot.val()
if(snapshot.val().name == this.state.temp_logged_name) {
user._id = 1;
user.name = temp_data.name;
user.avatar = temp_data.avatar;
}
const message = {
_id,
createdAt,
text,
user,
};
return message;
};
I had encountered this issue as well. I had set up react-native-gifted-chat on my mobile app. And at the other end I had set up a simple HTML page with a script to initialise the Websocket connection and send messages on the onsend event. What I had realised later that while the unique id was getting generated at the app end (because the id was being generated by the library itself), nothing of such sort existed at the other end.
Basically, this weird behaviour crops up when a unique id _id is missing for a message. Each message must have at least the following properties while executing GiftedChat.append(previousMessages, messages).
{
_id: 1,
text: 'Hello developer',
createdAt: new Date(),
user: {
_id: 2
}
}
There could be two reasons behind it,
1) Each message should be passed a unique id, so just use uuidv4 npm package and append it to _id prop of the object.
Example:
messages: GiftedChat.append(previousState.messages, {
_id: uuidv4(), // or use Math.round(Math.random() * 1000000)
text: text,
createdAt: new Date(),
user: {
_id: 2,
name: "React Native",
avatar: "https://placeimg.com/140/140/any"
},
image: attachment
})
2) Second possibility could be on the gateway you are using to initiate the chat between users. So, some gateways have known issues to repeat the message multiple times. You could to string comparison each time a new message is received and pushed to the chat screen, however it is not advised to do this.
I figured this out by simply applying the filter to the incoming message in useLayout Effect:
useLayoutEffect(() => {
db.collection('Chats').doc(docID).collection('messages').orderBy("createdAt", "desc").onSnapshot(snapshot => {
setMessages(
prev =>
prev
.filter((ftr,index,self) => ftr?.user?._id !== loginUser?.id) //login user id is the current user's id you can do the same for recieved messages
.concat
(snapshot.docs.map(doc => doc.data({
_id: doc?.id,
user: doc.data().user,
text: doc.data().text,
createdAt:new Date(doc.data().createdAt),
})
))
)
})
},[])
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Update: I've gotten a fair bit further. Please see the bottom of the post...
I'm working on a project that is based on the sql-fullstack yeoman generator, and have been using the included example code as a guide. Things have progressed smoothly, for the most part, but I'm now in a scenario where I have two tables/models with a bidirectional n:m relationship:
TaskGroup:
module.exports = function(sequelize, DataTypes) {
var TaskGroup = sequelize.define("TaskGroup", {
taskGroupID: {
field: "TaskGroupID",
type: DataTypes.INTEGER,
allowNull: false,
unique: true,
autoIncrement: true,
primaryKey: true
},
name: {
field: "Name",
type: DataTypes.STRING,
allowNull: false
},
description: {
field: "Description",
type: DataTypes.STRING
},
modifiedBy: {
field: "ModifiedBy",
type: DataTypes.STRING
}
});
and Task:
module.exports = function(sequelize, DataTypes) {
var Task = sequelize.define("Task", {
taskID: {
field: "TaskID",
type: DataTypes.INTEGER,
allowNull: false,
unique: true,
autoIncrement: true,
primaryKey: true
},
name: {
field: "Name",
type: DataTypes.STRING,
allowNull: false
},
description: {
field: "Description",
type: DataTypes.STRING
},
isOnRunsheet: {
field: "IsOnRunsheet",
type: DataTypes.BOOLEAN
},
modifiedBy: {
field: "ModifiedBy",
type: DataTypes.STRING
}
});
Relationships:
// Tasks can belong to more than one group, and groups can belong to more than one task
db['TaskGroup'].belongsToMany(db['Task'], {as: 'Tasks', through: 'TaskGrouping'});
db['Task'].belongsToMany(db['TaskGroup'], {as: 'TaskGroups', through: 'TaskGrouping'});
On the client side, the user is able to create a new task and specify the associated task groups through a multiple select list. When the task is saved, I have both the task fields and an array of the associated task groups. A post is made with the request body containing this information, so that the server can create the task record.
Unfortunately, I can't seem to get the record created. I've been through a number of iterations, and I'm at the point where I get what appears to be a reasonable exception - I'm just stumped as to what the "reasonable" thing to do is...
Exception:
Unhandled rejection SequelizeDatabaseError: Cannot insert the value NULL into column 'TaskTaskID', table 'HelpCard
.dbo.TaskGrouping'; column does not allow nulls. INSERT fails.
at Query.formatError (C:\Projects\helpcard2\node_modules\sequelize\lib\dialects\mssql\query.js:215:10)
at Request.userCallback (C:\Projects\helpcard2\node_modules\sequelize\lib\dialects\mssql\query.js:66:25)
at Request.callback (C:\Projects\node_modules\tedious\lib\request.js:33:27)
at Connection.message (C:\Projects\node_modules\tedious\lib\connection.js:1179:27)
at Connection.dispatchEvent (C:\Projects\node_modules\tedious\lib\connection.js:519:45)
at MessageIO.<anonymous> (C:\Projects\node_modules\tedious\lib\connection.js:439:23)
at emitNone (events.js:67:13)
at MessageIO.emit (events.js:166:7)
at ReadablePacketStream.<anonymous> (C:\Projects\node_modules\tedious\lib\message-io.js:92:15)
at emitOne (events.js:77:13)
...
Here's the code on the client side:
$scope.createTask = function() {
if($scope.newTask === '') {
return;
}
$scope.newTask.modifiedBy = 'tkturney';
var taskBundle = {
task: $scope.newTask,
taskGroups: $scope.selectedGroups
};
$http.post('/api/tasks', taskBundle);
setTimeout(function() {
$scope.currentTask = $scope.newTask;
$scope.newTask = '';
$scope.addingTask = false;
refreshTasks();
}, 250);
};
...and on the server side:
exports.create = function(req, res) {
var task = Task(req).build(req.body.task);
task.setTaskGroups(req.body.taskGroups);
task
.save()
.then(function() {
return res.status(201).json(task);
})
.catch(function (err){
if(err) { return handleError(res, err); }
});
};
I'm sure that I'm missing something obvious, but the documentation that I've found has been pretty light on a scenario like this. I would appreciate any guidance; I'm just getting into sequelize, and I feel that there are times that I may have bitten off more than I can chew... :)
Update: After taking a closer look at the SQL, I discovered that the exception was being thrown when trying to insert into the join table (TaskGroupings). It was trying to insert a NULL for the task's primary ID, which is generally not a good thing. Looking at the code, I realized that I was trying to add the association before I had saved the record, leaving me with no PK. Moving the task.addTaskGroups() after the save() took care of that issue.
However, I also realized that I was passing an array of TaskGroup objects to the 'addTaskGroup()` call, instead of the actual IDs. So, I modified the client-side controller like so:
$scope.createTask = function() {
if($scope.newTask === '') {
return;
}
$scope.groupKeys = [];
angular.forEach($scope.selectedGroups, function(taskGroup) {
$scope.groupKeys.push(taskGroup.taskGroupID);
});
$scope.newTask.modifiedBy = 'tkturney';
var taskBundle = {
task: $scope.newTask,
taskGroups: $scope.groupKeys
};
$http.post('/api/tasks', taskBundle);
...
When I look at the debugger, I can see everything in the taskGroup object, but taskGroup.taskGroupID is coming back as undefined, so I'm still getting an exception because I'm not passing the PKs for the other side of the association.
Does anything leap out as to what might be screwy with this code fragment?
Ok, by changing the server-side controller from this:
exports.create = function(req, res) {
var task = Task(req).build(req.body.task);
task.setTaskGroups(req.body.taskGroups);
task
.save()
.then(function() {
return res.status(201).json(task);
})
.catch(function (err){
if(err) { return handleError(res, err); }
});
};
To this:
exports.create = function(req, res) {
var task = Task(req).build(req.body.task);
task
.save()
.then(function() {
task.setTaskGroups(req.body.taskGroups);
return res.status(201).json(task);
})
.catch(function (err){
if(err) { return handleError(res, err); }
});
};
That particular exception went away. The thing that I was missing (though it was staring me in the face) was the fact that there are two separate inserts happening - one for the task, and one for the association. I was thinking that I needed to set the association before saving the task, not realizing that setting that association caused another insert.
I still need to figure out why the PKs for the other side of the association aren't getting populated, but that's outside the scope of the original question...
There's a dev database already set up for another project. I'm trying to create a sails.js server to connect to this database and act as a RESTful API. I'm also using SQL Workbench with the profile below to connect to the database and verify my query statements. On that tool, I'm able to send queries like select top 10 * from advisor and get the data I expect in response.
My connection configuration in sails.js seems to be alright, since I'm able to start the server. I've gotten simple static actions to work, like hi: function (req, res) { return res.send("Hi there!"); }. However, I can't figure out what to do to get a response from the database served by sails. My goal (at this point) is to have http://localhost:1337/advisor return JSON for the results of select top 10 * from advisor.
I initially tried using the freshly-generated model. Then, I tried adding attributes to the model file. Then, I tried adding my own code to the controller. In each case, the browser never received a response. At the end, I tested /advisor/list to run my own code and it doesn't look like the query() callback was ever executed. In case it's the first question, I have run npm install sails-sqlserver and I've double-checked that my host, db, username, & password are identical to what was used in Workbench.
connections.js
sqlserver: {
adapter: 'sails-sqlserver',
user: 'myusername',
password: 'mypassword',
host: 'mysubdomain.mydomain.net:1433',
database: 'frontofficedev'
}
models.js
module.exports.models = {
connection: 'sqlserver',
migrate: 'safe'
};
api\models\Advisor.js
module.exports = {
attributes: {
advcode: 'string',
advname: 'string',
'adv-default': 'boolean',
"user-id": 'string',
"pc-code": 'string',
"adv-tag": 'string',
"is-group": 'boolean',
"trade-grouping": 'string',
AdvisorId: 'int',
orgcode: 'string',
BranchId: 'int',
OrdPrnBranchId: 'int',
zdec1: 'float',
zdec2: 'float',
zchar1: 'string',
zchar2: 'string',
zchar3: 'string',
zchar4: 'string',
AdvStatus: 'string'
}
};
api\controllers
module.exports = {
hi: function (req, res) {
return res.send("Hi there!");
},
list: function (req, res) {
var myQuery = "select TOP 10 * from advisor";
sails.log.debug("Query :", myQuery);
console.log(Advisor);
Advisor.query(myQuery, function (err, advisors){
console.log(advisors);
console.log(err);
if(err || !advisors.rows.length){
return res.json({"status": 0, "error": err});
}
else{
return res.json(advisors);
}
});
}
};
Any ideas on what I'm doing wrong? Is JDBC causing problems? Thanks in advance.
Im assuming you've already run: npm install sails-sqlserver --save
You have to specify your connection and the table you will be using in the model, the variables in the model should match with your DB variables, like this:
api\models\Advisor.js
module.exports = {
schema: true,
connection: 'sqlserver',
tableName: 'yourTableName',
attributes: {
advcode:{
type: 'string',
primaryKey: true //if this is a primary key
},
advname:{
type: 'string'
},
'adv-default':{
type: 'boolean'
}
};
In your controller you can use the Sails ORM waterline like this:
api\controllers
module.exports = {
list: function (req, res) {
Advisor.query('SELECT * FROM advisor', function(err, results) {
if (err) {
res.send(400);
} else {
res.send(results);
}
});
}
};
Where Advisor is the model.
For more specific information about models and ORM waterline i recommend you read the sails docs: http://sailsjs.org/documentation/reference/waterline-orm/models
My colleague spotted the problem. The port that database lives on needs to be a separate attribute in sails' connection.js (instead of including it in the host string). No need for extra libraries, like node-jdbc.
config/connections.js
sqlserver: {
adapter: 'sails-sqlserver',
user: 'myusername',
password: 'mypassword',
host: 'mysubdomain.mydomain.net',
port: 1433,
database: 'frontofficedev'
}
After making that change, I was able to delete all my custom code from the controller and almost everything from the model (I still need to specify a primary key, since sails looks for id by default and the database was using AdvisorId.
api/models/Advisor.js
module.exports = {
attributes: {
AdvisorId: {primaryKey: true}
}
};