web-dev-qa-db-fra.com

Sequelize, convertit l'entité en objet simple

Je ne suis pas très familier avec javascript et stupéfiant, parce que je ne peux pas ajouter de nouvelle propriété à un objet extrait de la base de données à l'aide des noms ORM Sequelize.js.

Pour éviter cela, j'utilise ce 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);
});

Alors, comment normalement ajouter de nouvelles propriétés à un objet?.

Si cela peut aider, j'utilise la version 2.0.x de Sequelize-postgres.

pd. 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] } } }

Je pense ensuite ce que vous pensez: "Ok, c'est facile, ajoutez simplement votre propriété à dataValues."

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

J'ajoute ces lignes, et ça ne marche pas

66
Ruslan

Si je vous comprends bien, vous souhaitez ajouter la collection sensors à la collection node. Si vous avez un mappage entre les deux modèles, vous pouvez utiliser la fonctionnalité includeexpliquée ici ou le values getter défini. sur chaque instance. Vous pouvez trouver la documentation pour cela ici .

Ce dernier peut être utilisé comme ceci:

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

Il y a une chance que nodedata.sensors = sensors pourrait également fonctionner.

36
sdepold

vous pouvez utiliser les options de requête {raw: true} pour renvoyer le résultat brut. Votre requête devrait ressembler à ceci:

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

Pour ceux qui rencontrent cette question plus récemment, .values Est obsolète à partir de Sequelize 3.0.0. Utilisez .get() à la place pour obtenir l'objet javascript simple. Donc, le code ci-dessus deviendrait:

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

Sequelize docs ici

87
CharlesA

Comme CharlesA le note dans sa réponse, .values() est techniquement déconseillé , bien que ce fait ne soit pas explicitement mentionné dans les docs . Si vous ne souhaitez pas utiliser { raw: true } Dans la requête, l'approche recommandée consiste à appeler .get() sur les résultats.

.get(), cependant, est une méthode d'instance et non de tableau. Comme indiqué dans le problème lié ci-dessus, Sequelize renvoie des tableaux natifs d'objets d'instance (et les responsables ne prévoient pas de le changer). Vous devez donc parcourir le tableau vous-même:

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

Le meilleur moyen de faire est:

Il suffit d'utiliser le chemin par défaut de Sequelize

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

Remarque: [options.raw]: renvoie le résultat brut. Voir sequelize.query pour plus d'informations.


Pour le résultat imbriqué/si nous avons un modèle d'inclusion, dans la dernière version de 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);
});
24
Vivek Doshi

Voici ce que j'utilise pour obtenir un objet de réponse simple avec des valeurs non stringifiées et toutes les associations imbriquées à partir de la requête sequelize v4.

Avec JavaScript simple (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);
};

Avec lodash (un peu plus concis):

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

sage:

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

vous pouvez utiliser la fonction map. cela a fonctionné pour moi.

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

J'ai trouvé une solution qui fonctionne bien pour les modèles et les tableaux imbriqués à l'aide de fonctions JavaScript natives.

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
6
Suben Saha