Sequelize,将实体转换为普通对象

时间:2014-02-22 23:02:46

标签: node.js sequelize.js

我对javascript并不是很熟悉,令人惊叹,因为我无法使用ORM名称Sequelize.js从数据库中添加新属性到对象。

为了避免这种情况,我使用了这个黑客:

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

那么,通常的方法是向对象添加新属性。

如果它可以提供帮助,我使用sequelize-postgres版本2.0.x。

UPD。的console.log(节点):

{ 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] } } }

接下来我想你会想到:“好的,这很容易,只需将你的属性添加到dataValues。”

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

我添加了这一行,但这不起作用

11 个答案:

答案 0 :(得分:96)

您可以使用查询选项{raw: true}来返回原始结果。您的查询应如下所示:

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

答案 1 :(得分:85)

对于那些最近遇到此问题的人来说,自{Sequelize 3.0.0}以来.values已被弃用。使用.get()来获取普通的javascript对象。所以上面的代码将改为:

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

在这里发布docs

答案 2 :(得分:34)

如果我说得对,您想要将sensors集合添加到node。如果两个模型之间有映射,则可以使用include功能explained here或每个实例上定义的values getter。您可以找到文档for that here

后者可以像这样使用:

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

nodedata.sensors = sensors也有可能发挥作用。

答案 3 :(得分:25)

正如CharlesA在答案中指出的那样,.values()technically deprecated,尽管docs中没有明确指出这一事实。如果您不想在查询中使用{ raw: true },首选方法是在结果上调用.get()

但是,

.get()是实例的方法,而不是数组的方法。如上面链接的问题所述,Sequelize返回实例对象的本机数组(并且维护者不打算更改它),因此您必须自己遍历数组:

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

答案 4 :(得分:22)

最好和简单的做法是:

只需使用 Sequelize

中的默认方式即可
<?php
if ($this->item->catid == 9) { 
    echo "yes, it exists"; 
    } 
    else { 
    echo "no, it don't exist"; 
    }
?>
  

注意:[options.raw]:返回原始结果。有关更多信息,请参阅sequelize.query   信息。

答案 5 :(得分:6)

这是我用来获取具有非字符串化值的普通响应对象以及来自sequelize v4查询的所有嵌套关联的内容。

使用纯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);
};

lodash (更简洁一点):

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

<强>用法

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

答案 6 :(得分:5)

我找到了一个适用于使用本机JavaScript函数的嵌套模型和数组的解决方案。

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

答案 7 :(得分:4)

或者您可以使用地图功能。这对我有用。像这样:

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

答案 8 :(得分:2)

如果您希望所有查询都发生,您也可以尝试此操作:

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

访问Setting all queries to raw = true sequelize

答案 9 :(得分:0)

对于嵌套的JSON纯文本

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

答案 10 :(得分:0)

回答有点晚,但万一有人遇到这个问题并需要解决方案......

(假设这是在 async/await 函数中)

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

您可以查询并返回它是一个普通对象、对象数组等...