Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return flat object from sequelize with association

I am working on converting all my queries in sequelize. The problem I have come across is that when select queries include associations (ex. one to many), the object I get is an array of nested objects.

It looks something like:

[   
  {
    "field1": "someval",
    "field2": "someval1",
    "assoc_table": {
      "field_a": 1,
      "field_b": "someval"
    }   
  },   
  {
    "field1": "someval",
    "field2": "someval3",
    "assoc_table": {
      "field_a": 5,
      "field_b": "someval"
    }   
  },   
  {
    "field1": "someval",
    "field2": "someval3",
    "assoc_table": {
      "field_a": 12,
      "field_b": "someval"
    }   
   } 
]

I tried to use different modules to flatten the objects (inside a loop, each object individually), but I always got an error telling that what I was trying to flatten were not just objects.

Moreover, I would prefer avoiding the part where objects are flattened, and simply get a flat result with sequelize.

The sequelize code looks something like this:

models.table1.findAll({
    attributes: ['field1', 'field2'],
    where: {field1: someval},
    include: [{model: models.assoc_table, required: true, attributes:['field_a', 'field_b']}]
}).then(function (result) {
    res.send(result);
}).catch(function(error) {
    console.log(error);
});
like image 743
Lazarus Rising Avatar asked Jan 06 '17 09:01

Lazarus Rising


3 Answers

Part of your issue is probably that your result is an array of model instances, so you might be having issues flattening it if you didn't call toJSON on the elements in the array. I provided code that would flatten your example:

result.forEach(obj => { 
    Object.keys(obj.toJSON()).forEach(k => {
        if (typeof obj[k] === 'object') {       
            Object.keys(obj[k]).forEach(j => obj[j] = obj[k][j]);
        }
    });
});

You can also add raw: true as an option to findAll, which will flatten your object, but it will look like this:

[   
  {
    "field1": "someval",
    "field2": "someval1",
    "assoc_table.field_a": 1,
    "assoc_table.field_b": "someval"
  },
  ...
]
like image 177
jjbskir Avatar answered Oct 19 '22 06:10

jjbskir


Old question, but as I was attempting to do this also and found a pure sequelize solution that does not require the "after" mapping, I wanted to add that here. So to have sequelize itself return the desired object format, it would be this, where the attributes are explicitly assigned based off column return values from the include table:

models.table1.findAll({
    attributes: [
      'field1', 
      'field2',
      [sequelize.col('models.assoc_table.field_a'), 'field_a'], // Set key
      [sequelize.col('models.assoc_table.field_b'), 'field_b'], // Set key
    ],
    where: {field1: someval},
    include: [
     {model: models.assoc_table, 
      required: true, 
      attributes:[], // Explicitly do not send back nested key's
     }
   ]
})
like image 42
ScottS Avatar answered Oct 19 '22 07:10

ScottS


old question, but with new sequelize updates, use both:

raw:true,
nest:true
like image 44
Hiệp Nguyễn Avatar answered Oct 19 '22 07:10

Hiệp Nguyễn