'Sequelize JSON data type
I have defined a model as
module.exports = function (sequelize, DataTypes) {
const MyModel = sequelize.define('MyModel', {
data: {
type: DataTypes.JSON,
...
},
...
});
return MyModel;
};
I query it using
MyModel.findAll().then(myModels => ...);
However, data field in the query result is a string, not a JSON object. How do I fix it?
Solution 1:[1]
It's not supported yet MySQL JSON Data Type #4727. But you can do something like this:
module.exports = function (sequelize, DataTypes) {
const MyModel = sequelize.define('MyModel', {
data: {
type: Sequelize.TEXT,
get: function () {
return JSON.parse(this.getDataValue('value'));
},
set: function (value) {
this.setDataValue('value', JSON.stringify(value));
},
,
...
},
...
});
return MyModel;
};
I also found this package on github sequelize-json you can give it a try if you don't want to use getters and setters.
Solution 2:[2]
No need to use getters and setters as JSON is now supported by sequelize.See sequelize api
Solution 3:[3]
Jalal's answer was great but didn't work for me unless I tweaked it a little. Here's what worked for me:
First: create a migration that adds the field you want as type TEXT.
example - I want to add a field called address to the Stores table:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.addColumn("Stores", "address", Sequelize.TEXT);
},
down: (queryInterface, Sequelize) => {
return queryInterface.removeColumn("Stores", "address");
}
};
Next: Inside your model, add the field with getters and setters to your list (object) of fields and datatypes:
address: {
type: DataTypes.TEXT,
get: function() {
return JSON.parse(this.getDataValue("address"));
},
set: function(value) {
return this.setDataValue("address", JSON.stringify(value));
}
},
So my entire model looks like this:
module.exports = (sequelize, DataTypes) => {
const Store = sequelize.define(
"Store",
{
name: DataTypes.STRING,
isActive: DataTypes.BOOLEAN,
address: {
type: DataTypes.TEXT,
get: function() {
return JSON.parse(this.getDataValue("address"));
},
set: function(value) {
return this.setDataValue("address", JSON.stringify(value));
}
}
},
{}
);
Store.associate = function(models) {
// associations can be defined here
Store.hasMany(models.Order, {
foreignKey: "id",
targetKey: "storeId"
});
};
return Store;
};
Now you can create and retrieve records just like you would with a JSON type field in the db.
For example: const store = await Store.create({name: "Joe's corner store", address: {address1: "123 test street", city: "Los Angeles", state: "CA"}})
Some notes:
In the above code blocks...
- Replace
addresswith the field name you want to use. - Replace
Storeswith your model/table name. - I added
returnon the setter, otherwise it was erroring out when trying to create a new record (the way Jalal has it).
Solution 4:[4]
While this question is tagged MySQL, I suspect some people using MariaDB might end up here anyway, especially since MariaDB is now the default in many places. There's a difference in how the JSON data type is treated between MySQL and MariaDB, which is why sequelize implements it differently for these two DBs.
In my case I fixed this issue by explicitly switching sequelize to dialect mariadb. This requires you to install the mariadb package instead of mysql2. Afterwards my JSON columns were correctly parsed to an object.
Solution 5:[5]
JSON data types aren't supported for MySQL.
See the docs here http://docs.sequelizejs.com/en/v3/docs/models-definition/#data-types
A work around could be to use text and stringify/parse when querying it
Solution 6:[6]
The easiest solution is to use this little library called sequelize-json
Create a database and a Schema:
var Sequelize = require('sequelize'),
JsonField = require('sequelize-json'),
db,
User;
db = new Sequelize('database', 'username', 'password', {
dialect: 'sqlite',
logging: false
});
User = db.define('User', {
username: Sequelize.STRING,
jsonField: JsonField(db, 'User', 'jsonField')
});
Note the parameters of JsonField, you pass your Sequelize instance, the name of the model, and the name of the field. A little awkard, but this is needed in order to add the proper hooks to the model instance.
Now, you can always treat that field as a json object:
User.create({
username: 'Scott',
jsonField: {
likes: ['running', 'node']
}
})
.then(function(user) {
user.jsonField.likes.push('tests');
return user.save();
})
.then(function(user) {
expect(user.jsonField).to.be.a('object');
expect(user.jsonField.likes).to.have.length(3);
});
Solution 7:[7]
in sequelize v6, no need to use JSON.parse() since it returns Object itself.
Solution 8:[8]
Thank you ! I made further changes with the provided code above,
myColData:{
type:DataTypes.TEXT,
get:function(){
return JSON.parse(this.getDataValue("myColData"));
},
set:function(value){
return this.setDataValue("myColData", value);
}
}
I think it works fine if we don't stringify the data in the setter function If you stringify in the setter you might have to parse it again when you actully fetch the data.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jalal |
| Solution 2 | sharad shetty |
| Solution 3 | Ira Herman |
| Solution 4 | jlh |
| Solution 5 | redeye |
| Solution 6 | |
| Solution 7 | Naveen |
| Solution 8 | Lakpa Sherpa |
