Sắp xếp thứ tự, chuyển đổi thực thể thành đối tượng thuần túy


95

Tôi không rành về javascript và tuyệt vời, vì tôi không thể thêm thuộc tính mới, vào đối tượng, được tìm nạp từ cơ sở dữ liệu bằng cách sử dụng ORM tên Sequelize.js.

Để tránh điều này, tôi sử dụng hack này:

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

Vì vậy, cách thông thường để thêm các thuộc tính mới vào đối tượng.

Nếu nó có thể giúp được, tôi sử dụng phiên bản tiếp theo-postgres 2.0.x.

cập nhật. console.log (nút):

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

Tôi nghĩ tiếp theo, những gì bạn nghĩ sẽ là: "Ok, điều đó thật dễ dàng, chỉ cần thêm thuộc tính của bạn vào dataValues."

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

Tôi thêm dòng này, và nó không hoạt động


nodekhông được là đối tượng truyền thống. Có lẽ nó là một Buffer? Những gì hiện console.log(node);trước dòng nói lừa của bạn?
Kevin Reilly

Vui lòng xem bài cập nhật.
Ruslan

Câu trả lời:


43

Nếu tôi hiểu đúng, bạn muốn thêm sensorsbộ sưu tập vào node. Nếu bạn có một ánh xạ giữa cả hai mô hình, bạn có thể sử dụng includechức năng được giải thích ở đây hoặc valuesgetter được xác định trên mọi trường hợp. Bạn có thể tìm thấy tài liệu cho điều đó ở đây .

Cái sau có thể được sử dụng như thế này:

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

Có cơ hội nodedata.sensors = sensorscũng có thể hoạt động.


2
Cảm ơn bạn, tất cả những gì tôi cần: node.values ​​:)
Ruslan

148

bạn có thể sử dụng các tùy chọn truy vấn {raw: true}để trả về kết quả thô. Truy vấn của bạn sẽ như sau:

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

cũng như nếu bạn có mối liên hệ với includeđiều đó bị san bằng. Vì vậy, chúng ta có thể sử dụng một tham số khácnest:true

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

32
"raw: true" bằng cách nào đó sẽ làm phẳng mảng được đưa vào bởi các mô hình liên quan. Công việc duy nhất mà tôi tìm thấy cho đến nay là configs = JSON.parse (JSON.stringify (configs));
Soichi Hayashi

1
Đó là cách tiếp cận đơn giản và tốt hơn câu trả lời được chấp nhận. cảm ơn
pyprism

1
@SoichiHayashi Thực ra thì ngược lại khi bạn nghĩ về nó ...;) Không có raw: true, Sequelize bằng cách nào đó giải phóng kết quả thành các đối tượng. Kết quả từ truy vấn sql đã được làm phẳng. Tôi thấy nó hữu ích một vài lần để nhận được kết quả không đổi ... +1 cho câu trả lời này.
PRS

4
@SoichiHayashi để lấy kết quả thô nhưng lồng vào nhau, bạn có thể sử dụng nest: truecùng với raw: true.
1valdis

bất kỳ ý tưởng nào về cách chuyển raw:truedưới dạng cài đặt toàn cục, vì vậy không cần phải chuyển nó cho mọi truy vấn? Cảm ơn
codebot

111

Đối với những người gặp câu hỏi này gần đây hơn, .valueskhông được dùng nữa kể từ Sequelize 3.0.0. .get()Thay vào đó, hãy sử dụng để lấy đối tượng javascript thuần túy. Vì vậy, mã trên sẽ thay đổi thành:

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

Sắp xếp chuỗi tài liệu tại đây


6
Hãy sửa cho tôi nếu tôi sai - nhưng tôi không nghĩ điều này sẽ hoạt động với một mảng hàng? Ví dụ: với .findAndcount, bạn phải. Ánh xạ các hàng kết quả và trả về .get trên mỗi hàng để nhận được những gì bạn cần.
backdesk

Có lẽ dễ dàng hơn chỉ cần chạy JSON.stringify hoặc res.json (nếu bạn đang làm việc trong express).
backdesk

@backdesk - chưa thử nó trên một mảng - nhưng từ tài liệu, có vẻ như nó sẽ trả về cùng một thứ.
CharlesA

3
Sử dụng .get()sẽ không chuyển đổi các liên kết được bao gồm, hãy sử dụng .get({ plain: true })thay thế. Cảm ơn đã đề cập đến đề xuất từ ​​các tài liệu.
Wumms

Cũng hữu ích nếu bạn đã thực hiện truy vấn và do đó không thể xảy ra sự cốraw: true
Matt Molnar

49

Cách tốt nhất và đơn giản để làm là:

Chỉ cần sử dụng cách mặc định từ Sequelize

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

Lưu ý: [options.raw]: Trả về kết quả thô. Xem phần tiếp theo.query để biết thêm thông tin.


Đối với kết quả lồng nhau / nếu chúng ta có mô hình bao gồm, Trong phiên bản mới nhất của 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);
});

Câu trả lời này rất hữu ích, sử dụng chức năng gốc được cung cấp bởi sequleize, trong trường hợp của tôi khi tôi gửi nhiều hơn một hàng trong socket, đã xảy ra lỗi tràn ngăn xếp.
Ashish Kadam

2
Nếu bạn có một mảng dữ liệu con, bạn sẽ nhận được kết quả sai. Vì vậy, nếu gửi truy vấn trả về chỉ có một sensorsvới một mảng của con someModel, bạn sẽ nhận được một arraysố sensorsvới một someModeltrong mỗi.
Rahmat Ali

31

Như ghi chú CharlesA trong câu trả lời của mình, .values()về mặt kỹ thuật bị phản đối , mặc dù thực tế này không được nêu rõ trong các tài liệu . Nếu bạn không muốn sử dụng { raw: true }trong truy vấn, cách tiếp cận ưu tiên là gọi.get() kết quả.

.get()tuy nhiên, là một phương thức của một thể hiện, không phải của một mảng. Như đã lưu ý trong vấn đề được liên kết ở trên, Sequelize trả về mảng gốc của các đối tượng cá thể (và người bảo trì không có kế hoạch thay đổi điều đó), vì vậy bạn phải tự mình lặp qua mảng:

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

Điều này đã làm việc cho tôi! Mặc dù tôi không biết liệu 'get' là một JavaScript hay một hàm Sequelize. Vui lòng làm sáng tỏ cho tôi. Cảm ơn
antew

1
@antew Đó là một phương thức trên một đối tượng được trả về từ cơ sở dữ liệu - nó là một phần của thư viện phần tiếp theo, không phải là một hàm javascript gốc.
Shane Hughes

Đã khiến tôi mất nhiều tuổi để làm việc này! Cảm ơn bạn. Rất khó vì tôi có rất nhiều bao gồm lồng vào nhau, đó cũng là một lỗi. Vì vậy, tôi phải thực hiện nhiều truy vấn, và tôi không thể vì điều này !!!
Karl Taylor

17

bạn có thể sử dụng chức năng bản đồ. điều này được làm việc cho tôi.

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

Cảm ơn đây là giải pháp tốt nhất cho dàn diễn viên sử dụng của tôi, chỉresults = results.map(el => el.get({ plain: true }))
Joshua Ohana

9

Tôi đã tìm thấy một giải pháp hoạt động tốt cho mô hình và mảng lồng nhau bằng cách sử dụng các hàm JavaScript gốc.

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
Rất đơn giản, nhưng hoạt động mạnh mẽ và giữ cho mô hình logic. Tôi không biết nó hiệu quả như thế nào, nhưng nó đủ tốt cho tôi. Bạn có thể viết tắt nó thành một cái gì đó như: let res = JSON.parse (JSON.stringify (result));
Artipixel

9

Đây là những gì tôi đang sử dụng để nhận đối tượng phản hồi đơn giản với các giá trị không được xâu chuỗi và tất cả các liên kết lồng nhau từ sequelize truy vấn v4.

Với JavaScript đơn giản (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);
};

Với lodash (ngắn gọn hơn một chút):

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

Cách sử dụng :

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

1
Cảm ơn! ToPlain hoạt động như mong đợi và cũng giải quyết được vấn đề của tôi.
Erhnam

Điều này thật gọn gàng, nhưng sẽ không tốt nếu bạn ghi đè lên bất kỳ phương thức toJSON nào trong mô hình của bạn. Tôi làm điều này khá nhiều để xóa hoặc chuyển đổi các giá trị createAt / updatedAt. Cho đến nay, thứ duy nhất hoạt động bình thường đối với tôi là JSON.parse (JSON.stringify (response)).
hamham

2

Đối với văn bản thuần JSON lồng nhau

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

1
nó không hoạt động đề xuất cho một đến nhiều liên kết tốt hơn nên sử dụng .map (obj => obj.get ({trơn: true}))
Manav Kothari,

thực sự tôi đang nói về db.model.findOne và một đến nhiều hiệp hội.
Manav Kothari
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.