152

I'm not very familiar with javascript, and stunning, because i can't add new property, to object, that fetched from database using ORM names Sequelize.js.

To avoid this, i use this hack:

db.Sensors.findAll({ where: { nodeid: node.nodeid } }).success(function (sensors) { var nodedata = JSON.parse(JSON.stringify(node)); // this is my trick nodedata.sensors = sensors; nodesensors.push(nodedata); response.json(nodesensors); }); 

So, what normally way to add new properties to object.

If it can help, i use sequelize-postgres version 2.0.x.

upd. console.log(node):

{ dataValues: { nodeid: 'NodeId', name: 'NameHere', altname: 'Test9', longname: '', latitude: 30, longitude: -10, networkid: 'NetworkId', farmid: '5', lastheard: Mon Dec 09 2013 04:04:40 GMT+0300 (FET), id: 9, createdAt: Tue Dec 03 2013 01:29:09 GMT+0300 (FET), updatedAt: Sun Feb 23 2014 01:07:14 GMT+0300 (FET) }, __options: { timestamps: true, createdAt: 'createdAt', updatedAt: 'updatedAt', deletedAt: 'deletedAt', touchedAt: 'touchedAt', instanceMethods: {}, classMethods: {}, validate: {}, freezeTableName: false, underscored: false, syncOnAssociation: true, paranoid: false, whereCollection: { farmid: 5, networkid: 'NetworkId' }, schema: null, schemaDelimiter: '', language: 'en', defaultScope: null, scopes: null, hooks: { beforeCreate: [], afterCreate: [] }, omitNull: false, hasPrimaryKeys: false }, hasPrimaryKeys: false, selectedValues: { nodeid: 'NodeId', name: 'NameHere', longname: '', latitude: 30, longitude: -110, networkid: 'NetworkId', farmid: '5', lastheard: Mon Dec 09 2013 04:04:40 GMT+0300 (FET), id: 9, createdAt: Tue Dec 03 2013 01:29:09 GMT+0300 (FET), updatedAt: Sun Feb 23 2014 01:07:14 GMT+0300 (FET), altname: 'Test9' }, __eagerlyLoadedAssociations: [], isDirty: false, isNewRecord: false, daoFactoryName: 'Nodes', daoFactory: { options: { timestamps: true, createdAt: 'createdAt', updatedAt: 'updatedAt', deletedAt: 'deletedAt', touchedAt: 'touchedAt', instanceMethods: {}, classMethods: {}, validate: {}, freezeTableName: false, underscored: false, syncOnAssociation: true, paranoid: false, whereCollection: [Object], schema: null, schemaDelimiter: '', language: 'en', defaultScope: null, scopes: null, hooks: [Object], omitNull: false, hasPrimaryKeys: false }, name: 'Nodes', tableName: 'Nodes', rawAttributes: { nodeid: [Object], name: [Object], altname: [Object], longname: [Object], latitude: [Object], longitude: [Object], networkid: [Object], farmid: [Object], lastheard: [Object], id: [Object], createdAt: [Object], updatedAt: [Object] }, daoFactoryManager: { daos: [Object], sequelize: [Object] }, associations: {}, scopeObj: {}, primaryKeys: {}, primaryKeyCount: 0, hasPrimaryKeys: false, autoIncrementField: 'id', DAO: { [Function] super_: [Function] } } } 

I think next, what you think will be: "Ok, that is easy, just add your property to dataValues."

node.selectedValues.sensors = sensors; node.dataValues.sensors = sensors; 

I add this lines, and this don't work

0

12 Answers 12

246

you can use the query options {raw: true} to return the raw result. Your query should like follows:

db.Sensors.findAll({ where: { nodeid: node.nodeid }, raw: true, }) 

also if you have associations with include that gets flattened. So, we can use another parameter nest:true

db.Sensors.findAll({ where: { nodeid: node.nodeid }, raw: true, nest: true, }) 

enter image description here

Sign up to request clarification or add additional context in comments.

7 Comments

"raw: true" will somehow flattens array injected by associated models. The only work around I found so far is to configs = JSON.parse(JSON.stringify(configs));
That's simple and better approach than accepted answer. thanks
@SoichiHayashi Actually, its the reverse when you think about it... ;) Without raw: true, Sequelize somehow unflattens the result into objects. The results from the sql query are already flattened. I've found it useful a few times to get a flat result... +1 for this answer.
@SoichiHayashi to get raw but nested result, you can use nest: true along with raw: true.
any idea how to pass the raw:true as a global setting, so there is no need to pass it to every query? Thanks
|
152

For those coming across this question more recently, .values is deprecated as of Sequelize 3.0.0. Use .get() instead to get the plain javascript object. So the above code would change to:

var nodedata = node.get({ plain: true }); 

Sequelize docs here

6 Comments

Correct me if I'm wrong - but I don't think this will work with an array of rows? For example with .findAndcount you'd have to .map the result rows and return .get on each to get what you need.
Probably easier to just run JSON.stringify or res.json (if you're working within express).
@backdesk - haven't tried it on an array - but from the docs it looks like it should return the same thing.
Using .get() won't convert included associations, use .get({ plain: true }) instead. Thanks for mentioning the suggestion from the docs.
Also useful if you already performed the query and thus can't issue raw: true
|
60

Best and the simple way of doing is :

Just use the default way from Sequelize

db.Sensors.findAll({ where: { nodeid: node.nodeid }, raw : true // <----------- Magic is here }).success(function (sensors) { console.log(sensors); }); 

Note : [options.raw] : Return raw result. See sequelize.query for more information.


For the nested result/if we have include model , In latest version of sequlize ,

db.Sensors.findAll({ where: { nodeid: node.nodeid }, include : [ { model : someModel } ] raw : true , // <----------- Magic is here nest : true // <----------- Magic is here }).success(function (sensors) { console.log(sensors); }); 

3 Comments

This answer very useful, use native functionality provided by sequleize, in my case when i send more than one row in socket, stack overflow error happened.
If you have an array of child data, you will get wrong results. So, if posted query returns only one sensors with an array of child someModel, you will get an array of sensors with one someModel in each.
raw result also omits all VIRTUAL property values.
47

If I get you right, you want to add the sensors collection to the node. If you have a mapping between both models you can either use the include functionality explained here or the values getter defined on every instance. You can find the docs for that here.

The latter can be used like this:

db.Sensors.findAll({ where: { nodeid: node.nodeid } }).success(function (sensors) { var nodedata = node.values; nodedata.sensors = sensors.map(function(sensor){ return sensor.values }); // or nodedata.sensors = sensors.map(function(sensor){ return sensor.toJSON() }); nodesensors.push(nodedata); response.json(nodesensors); }); 

There is chance that nodedata.sensors = sensors could work as well.

1 Comment

Thank you, all i need: node.values :)
34

As CharlesA notes in his answer, .values() is technically deprecated, though this fact isn't explicitly noted in the docs. If you don't want to use { raw: true } in the query, the preferred approach is to call .get() on the results.

.get(), however, is a method of an instance, not of an array. As noted in the linked issue above, Sequelize returns native arrays of instance objects (and the maintainers don't plan on changing that), so you have to iterate through the array yourself:

db.Sensors.findAll({ where: { nodeid: node.nodeid } }).success((sensors) => { const nodeData = sensors.map((node) => node.get({ plain: true })); }); 

3 Comments

This worked for me! Though I don't know if 'get' is a JavaScript or a Sequelize function. Please enlighten me. Thanks
@antew It's a method on an object returned from the database - it's part of the sequelize library, not a native javascript function.
Took me ages to get to this working! Thank you. Was so difficult because I have a lot of nested includes, which is also a bug. So I have to do multiple queries, and I couldn't because of this!!!
23

you can use map function. this is worked for me.

db.Sensors .findAll({ where: { nodeid: node.nodeid } }) .map(el => el.get({ plain: true })) .then((rows)=>{ response.json( rows ) }); 

2 Comments

Thanks this was the best solution for my use cast, just results = results.map(el => el.get({ plain: true }))
I was searching for get({ plain: true }). Thanks!
12

Here's what I'm using to get plain response object with non-stringified values and all nested associations from sequelize v4 query.

With plain JavaScript (ES2015+):

const toPlain = response => { const flattenDataValues = ({ dataValues }) => { const flattenedObject = {}; Object.keys(dataValues).forEach(key => { const dataValue = dataValues[key]; if ( Array.isArray(dataValue) && dataValue[0] && dataValue[0].dataValues && typeof dataValue[0].dataValues === 'object' ) { flattenedObject[key] = dataValues[key].map(flattenDataValues); } else if (dataValue && dataValue.dataValues && typeof dataValue.dataValues === 'object') { flattenedObject[key] = flattenDataValues(dataValues[key]); } else { flattenedObject[key] = dataValues[key]; } }); return flattenedObject; }; return Array.isArray(response) ? response.map(flattenDataValues) : flattenDataValues(response); }; 

With lodash (a bit more concise):

const toPlain = response => { const flattenDataValues = ({ dataValues }) => _.mapValues(dataValues, value => ( _.isArray(value) && _.isObject(value[0]) && _.isObject(value[0].dataValues) ? _.map(value, flattenDataValues) : _.isObject(value) && _.isObject(value.dataValues) ? flattenDataValues(value) : value )); return _.isArray(response) ? _.map(response, flattenDataValues) : flattenDataValues(response); }; 

Usage:

const res = await User.findAll({ include: [{ model: Company, as: 'companies', include: [{ model: Member, as: 'member', }], }], }); const plain = toPlain(res); // 'plain' now contains simple db object without any getters/setters with following structure: // [{ // id: 123, // name: 'John', // companies: [{ // id: 234, // name: 'Google', // members: [{ // id: 345, // name: 'Paul', // }] // }] // }] 

4 Comments

Thanks! The toPlain works as expected and solved my issue as well.
This is neat, but it's no good if you override any of your model's toJSON methods. I do this quite a lot to either remove or convert the createdAt/updatedAt values. So far the only thing that has worked properly for me is JSON.parse(JSON.stringify(response)).
Your answer gave me a nudge to look deeper into Model's doc and toJSON. After fixing a custom getter in my model definition, toJSON worked well for me, so had no need for a custom implementation like yours.
I believe this is the only working solution. get({plain:true}) adds all non requested fields with undefined. {raw:true, nest:true} does not deal with 1:n nested associations well.
10

I have found a solution that works fine for nested model and array using native JavaScript functions.

var results = [{},{},...]; //your result data returned from sequelize query var jsonString = JSON.stringify(results); //convert to string to remove the sequelize specific meta data var obj = JSON.parse(jsonString); //to make plain json // do whatever you want to do with obj as plain json 

1 Comment

So simple, yet powerfully works and keeps the model logic. I don't know how efficient it is, but it was good enough for me. You can short it to something like: let res = JSON.parse(JSON.stringify(result));
7

For plain objects

db.model.findAll({ raw : true , nest : true }) 

5 Comments

it doesn't work propery for one to many association its better to use .map(obj => obj.get({ plain: true }))
actually i am talking about db.model.findOne and one to many association.
watch out, that doesn't give you json. it gives you plain objects.
brother it remove one to many relation
it is invalid when we use associate concept
3

It's a little late to answer, but in case someone runs across this question and needs a solution...

(Assuming this is in async/await function)

const sensors = JSON.parse(JSON.stringify(await db.Sensors.findAll({ where: { nodeid: node.nodeid } }))) 

You can query and return it is a plain object, array of objects, etc...

1 Comment

this answer is working for association also .. plus 1 added
2

You can also try this if you want to occur for all the queries:

var sequelize = new Sequelize('database', 'username', 'password', {query:{raw:true}}) 

Visit Setting all queries to raw = true sequelize

1 Comment

So - how does this work when you are doing an upsert?!
2

I use my own model mixin for handy responses

const camelcaseKeys = require('camelcase-keys'); const initMixins = Sequelize => { // Convert model to plain object and camelcase keys for response Sequelize.Model.prototype.toPlainObject = function({ camelcase = false } = {}) { const plain = this.get({ plain: true }); if (camelcase) { return camelcaseKeys(plain, { deep: true }); } else { return plain; } }; }; module.exports = { initMixins, }; // usage const userModel = await UserModel.findOne(); console.log(userModel.toPlainObject()); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.