Sırala, varlığı düz nesneye dönüştür


95

Javascript'e pek aşina değilim ve çarpıcı, çünkü ORM isimleri Sequelize.js kullanılarak veritabanından getirilen nesneye yeni özellik ekleyemiyorum.

Bundan kaçınmak için bu hack'i kullanıyorum:

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

Peki, nesneye yeni özellikler eklemenin normal yolu nedir?

Yardımcı olabilirse, sequelize-postgres 2.0.x sürümünü kullanıyorum.

upd. console.log (düğüm):

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

Sanırım bir sonraki adımda düşündüğünüz şey: "Tamam, bu kolay, sadece mülkünüzü dataValues'e ekleyin."

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

Bu satırları ekliyorum ve bu işe yaramıyor


nodegeleneksel bir nesne olmamalıdır. Belki bir Tampondur? Numaranızdan console.log(node);önce ne diyor?
Kevin Reilly

Lütfen güncelleme gönderisine bakın.
Ruslan

Yanıtlar:


43

Sizi doğru anlarsam, sensorskoleksiyonu node. Her iki model arasında bir eşlemeniz varsa, burada açıklananinclude işlevselliği veya her durumda tanımlanan alıcıyı kullanabilirsiniz . Bunun için dokümanları burada bulabilirsiniz .values

İkincisi şu şekilde kullanılabilir:

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İşe yarayabilecek bir şans var .


2
Teşekkürler, tek ihtiyacım olan: node.values ​​:)
Ruslan

147

{raw: true}Ham sonucu döndürmek için sorgu seçeneklerini kullanabilirsiniz . Sorgunuz aşağıdaki gibi olmalıdır:

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

Ayrıca, bununla ilişkileriniz varsa includedüzleşir. Yani başka bir parametre kullanabiliriznest:true

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

32
"raw: true", ilişkili modeller tarafından enjekte edilen diziyi bir şekilde düzleştirir. Şimdiye kadar bulduğum tek çalışma, configs = JSON.parse (JSON.stringify (configs));
Soichi Hayashi

1
Bu, kabul edilen cevaptan daha basit ve daha iyi bir yaklaşım. teşekkürler
pyprism

1
@SoichiHayashi Aslında, düşündüğünüzde tam tersi ...;) Ham olmadan: doğru, Sequelize bir şekilde sonucu nesnelere açıyor. Sql sorgusunun sonuçları zaten düzleştirildi. Birkaç kez düz bir sonuç elde etmeyi faydalı buldum ... Bu cevap için +1.
PRS

4
@SoichiHayashi ham ama iç içe sonuç almak için nest: truebirlikte kullanabilirsiniz raw: true.
1valdis

raw:truegenel bir ayar olarak nasıl geçirileceğine dair herhangi bir fikriniz var, bu yüzden onu her sorguya aktarmaya gerek yok mu? Teşekkürler
codebot

109

Bu soruyla daha yakın zamanda karşılaşanlar için, .valuesSequelize 3.0.0'dan itibaren kullanımdan kaldırılmıştır. .get()Bunun yerine düz javascript nesnesini almak için kullanın . Yani yukarıdaki kod şu şekilde değişecektir:

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

Belgeleri burada özetleyin


6
Yanılıyorsam düzelt - ama bunun bir dizi satırda işe yarayacağını düşünmüyorum? Örneğin .findAndcount ile, ihtiyacınız olanı elde etmek için sonuç satırlarını eşleştirmeniz ve her birinde .get döndürmeniz gerekir.
arka plan

JSON.stringify veya res.json'u çalıştırmak muhtemelen daha kolaydır (ekspres içinde çalışıyorsanız).
backdesk

@backdesk - bir dizide denemedim - ancak dokümanlardaki aynı şeyi döndürmesi gerekiyor gibi görünüyor.
CharlesA

3
Kullanımı .get()dahil edilen ilişkilendirmeleri dönüştürmez, .get({ plain: true })bunun yerine kullanın. Dokümanlardan gelen öneriden bahsettiğiniz için teşekkür ederiz.
Wumms

Ayrıca zaten sorgu yararlı yapıldığı takdirde ve böylece veremezraw: true
Matt Molnar

49

Yapmanın en iyi ve basit yolu:

Sequelize'deki varsayılan yolu kullanmanız yeterli

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

Not: [options.raw]: Ham sonucu döndürür. Daha fazla bilgi için sequelize.query'ye bakın.


İç içe geçmiş sonuç için / eğer model eklersek, sekansın son sürümünde,

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

Bu cevap çok kullanışlı, sıralı tarafından sağlanan yerel işlevselliği kullan, benim durumumda sokette birden fazla satır gönderdiğimde yığın taşma hatası oluştu.
Ashish Kadam

2
Bir dizi alt veriniz varsa, yanlış sonuçlar alırsınız. Sadece bir sorgu getiri yayınlanmıştır Yani eğer, sensorsçocuğun bir dizi someModel, bir alacak arrayait sensorsbiriyle someModelher birinde.
Rahmat Ali

31

CharlesA'nın cevabında belirttiği gibi , bu gerçek belgelerde açıkça belirtilmese .values()de teknik olarak reddedilmiştir . Sorguda kullanmak istemiyorsanız , tercih edilen yaklaşım sonuçları aramaktır.{ raw: true }.get()

.get()ancak, bir dizi değil, bir örneğin yöntemidir. Yukarıdaki bağlantılı konuda belirtildiği gibi, Sequelize örnek nesnelerinin yerel dizilerini döndürür (ve bakımcılar bunu değiştirmeyi planlamazlar), bu nedenle dizi boyunca kendiniz yinelemeniz gerekir:

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

Bu benim için çalıştı! "Get" in JavaScript mi ​​yoksa Sequelize işlevi mi olduğunu bilmiyorum. Lütfen beni aydınlat. Teşekkürler
antew

1
@antew Bu, veritabanından döndürülen bir nesne üzerindeki bir yöntemdir - bu, yerel bir javascript işlevi değil, sıralı hale getirme kitaplığının bir parçasıdır.
Shane Hughes

Bu işe başlamam yaşlarımı aldı! Teşekkür ederim. Çok zordu çünkü çok sayıda iç içe geçmiş içeriğim var, ki bu da bir hata. Bu yüzden birden fazla sorgu yapmam gerekiyor ve bu yüzden yapamadım !!!
Karl Taylor

17

harita işlevini kullanabilirsiniz. bu benim için çalıştı.

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

Teşekkürler, bu benim kullanımım için en iyi çözümdü, sadeceresults = results.map(el => el.get({ plain: true }))
Joshua Ohana

9

Yerel JavaScript işlevlerini kullanan iç içe model ve dizi için iyi çalışan bir çözüm buldum.

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
Çok basit, ancak güçlü bir şekilde çalışıyor ve model mantığını koruyor. Ne kadar verimli olduğunu bilmiyorum ama benim için yeterince iyiydi. Bunu şöyle bir şeye kısaltabilirsiniz: let res = JSON.parse (JSON.stringify (sonuç));
Artipixel

9

sequelizeV4 sorgusundan dizgisiz değerlere ve tüm iç içe ilişkilendirmelere sahip düz yanıt nesnesini almak için kullandığım şey burada .

İle düz 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);
};

İle lodash (daha özlü bit):

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

Kullanım :

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
Teşekkürler! ToPlain beklendiği gibi çalışıyor ve sorunumu da çözdü.
Erhnam

Bu harika, ancak modelinizin toJSON yöntemlerinden herhangi birini geçersiz kılarsanız iyi olmaz. Bunu, createdAt / updatedAt değerlerini kaldırmak veya dönüştürmek için oldukça sık yapıyorum. Şimdiye kadar benim için düzgün çalışan tek şey JSON.parse (JSON.stringify (response)).
hamham

2

İç içe yerleştirilmiş JSON düz metni için

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

1
birden çok dernek için düzgün çalışmıyor .map kullanmak daha iyidir (obj => obj.get ({plain: true}))
Manav Kothari

aslında db.model.findOne ve bire çok dernekten bahsediyorum.
Manav Kothari'yi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.