I have the following demo code written in Sequelize. I'd like to pull a list of Endpoint
entities get a list of EndpointCall
entities grouped by 1 minute time buckets. I can't seem to be able to solve this is Sequelize with a findAll with a nested table:
const Sequelize = require('sequelize');
const sequelize = new Sequelize(process.env.MYSQL_DATABASE, process.env.MYSQL_USER, process.env.MYSQL_PASSWORD, {
host: process.env.MYSQL_HOST,
dialect: 'mysql',
logging: false,
benchmark: false,
});
const model = {
Endpoint: sequelize.define('endpoint', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
name: { type: Sequelize.STRING('256'), allowNull: false },
}),
EndpointCall: sequelize.define('endpoint_call', {
endpoint_id: { type: Sequelize.INTEGER, allowNull: false },
date: { type: Sequelize.DATE, allowNull: false },
response_time: { type: Sequelize.DOUBLE, allowNull: true },
}),
init: function () {
this.Endpoint.hasMany(this.EndpointCall, { foreignKey: 'endpoint_id' });
return sequelize.sync();
},
};
model.init()
.then(async () => {
var result = await model.Endpoint.findAll({
include: [{
model: model.EndpointCall,
required: false,
attributes: [
[Sequelize.literal(`FROM_UNIXTIME(ROUND(UNIX_TIMESTAMP(date)/60)*60)`), 'time_bucket'],
[Sequelize.literal(`AVG(response_time)`), 'avg_response_time']
],
group: 'time_bucket'
}],
});
console.log(result);
});
This is the closest I got to but this still throws the following error:
In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'database.endpoint.id'; this is incompatible with sql_mode=only_full_group_by
I don't necessarily want to configure the MySQL server a non-standard way, therefore I was trying to play with the group
clause but with no luck:
group: [ 'id', 'name', 'time_bucket' ]
Moving the group clause to the top level table also didn't help.
UPDATE:
- Tried
group: [ 'endpoint_call.time_bucket' ]
on the top level
Result:
SequelizeDatabaseError: Unknown column 'endpoint_call.time_bucket' in 'group statement'
- Tried
group: [ 'endpoint_calls.time_bucket' ]
on the top level (with the -s at the end)
Result:
SequelizeDatabaseError: Unknown column 'endpoint_calls.time_bucket' in 'group statement'
WORKAROUND:
Thanks to Emma in the comments I found a workaround. I still thing that Sequelize should solve this internally, I'm publishing it here in case someone else gets stuck.
The point is removing sql_mode=only_full_group_by
in a local session by executing this before the aggregated query:
SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
The full code is here:
model.init()
.then(async () => {
await sequelize.query(`SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));`);
var result = await model.Endpoint.findAll({
include: [{
model: model.EndpointCall,
required: false,
separate: true,
attributes: [
[Sequelize.literal(`FROM_UNIXTIME(ROUND(UNIX_TIMESTAMP(date)/60)*60)`), 'time_bucket'],
[Sequelize.literal(`AVG(response_time)`), 'avg_response_time']
],
group: [ 'endpoint_id', 'time_bucket' ],
}],
});
console.log(result);
});