Sequelize, convert entity to plain object

node.jssequelize.js

node.js Problem Overview


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

node.js Solutions


Solution 1 - node.js

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,
})

Solution 2 - node.js

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

Solution 3 - node.js

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);
});

Solution 4 - node.js

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.

Solution 5 - node.js

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 }));
});

Solution 6 - node.js

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 )
     });

Solution 7 - node.js

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',
//     }]
//   }]
// }]

Solution 8 - node.js

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

Solution 9 - node.js

For plain objects

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

Solution 10 - node.js

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 https://stackoverflow.com/questions/26228499/setting-all-queries-to-raw-true-sequelize

Solution 11 - node.js

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());

Solution 12 - node.js

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...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRuslanView Question on Stackoverflow
Solution 1 - node.jslutaoactView Answer on Stackoverflow
Solution 2 - node.jsCharlesAView Answer on Stackoverflow
Solution 3 - node.jsVivek DoshiView Answer on Stackoverflow
Solution 4 - node.jssdepoldView Answer on Stackoverflow
Solution 5 - node.jsShane HughesView Answer on Stackoverflow
Solution 6 - node.jsnur zazinView Answer on Stackoverflow
Solution 7 - node.jsevenfrostView Answer on Stackoverflow
Solution 8 - node.jsSuben SahaView Answer on Stackoverflow
Solution 9 - node.jsAmr IbrahimView Answer on Stackoverflow
Solution 10 - node.jsHarsh PandeyView Answer on Stackoverflow
Solution 11 - node.jsBohdan YurchukView Answer on Stackoverflow
Solution 12 - node.jsHatem JaberView Answer on Stackoverflow