Использование group by и объединение в sequelize
У меня есть две таблицы в базе данных PostgreSQL, контрактах и платежах. В одном контракте сделано несколько платежей.
У меня есть две следующие модели:
module.exports = function(sequelize, DataTypes) {
var contracts = sequelize.define('contracts', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true
}
}, {
createdAt: false,
updatedAt: false,
classMethods: {
associate: function(models) {
contracts.hasMany(models.payments, {
foreignKey: 'contract_id'
});
}
}
});
return contracts;
};
module.exports = function(sequelize, DataTypes) {
var payments = sequelize.define('payments', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true
},
contract_id: {
type: DataTypes.INTEGER,
},
payment_amount: DataTypes.INTEGER,
}, {
classMethods: {
associate: function(models) {
payments.belongsTo(models.contracts, {
foreignKey: 'contract_id'
});
}
}
});
return payments;
};
Я хотел бы суммировать все платежи, сделанные за каждый контракт, и использовал эту функцию:
models.contracts.findAll({
attributes: [
'id'
],
include: [
{
model: models.payments,
attributes: [[models.sequelize.fn('sum', models.sequelize.col('payments.payment_amount')), 'total_cost']]
}
],
group: ['contracts.id']
})
Но он генерирует следующий запрос:
SELECT "contracts"."id", "payments"."id" AS "payments.id", sum("payments"."payment_amount") AS "payments.total_cost"
FROM "contracts" AS "contracts"
LEFT OUTER JOIN "payments" AS "payments" ON "contracts"."id" = "payments"."contract_id" GROUP BY "contracts"."id";
Я не прошу выбрать payments.id, потому что мне пришлось бы включать его в мою агрегацию или группу по функциям, как сказано в ошибке, которую я имею:
Возможно необработанное SequelizeDatabaseError: ошибка: столбец "payments.id" должен появиться в предложении GROUP BY или использоваться в агрегатной функции
Я что-то упустил? Я следую этому ответу, но даже там я не понимаю, как запрос SQL может быть действительным.
Ответы
Ответ 1
Эта проблема была исправлена в Sequelize 3.0.1, первичный ключ включенных моделей должен быть исключен с помощью
attributes: []
и агрегация должна быть выполнена на основной модели (информация в этой проблеме github).
Таким образом, для моего варианта использования код следующий
models.contracts.findAll({
attributes: ['id', [models.sequelize.fn('sum', models.sequelize.col('payments.payment_amount')), 'total_cost']],
include: [
{
model: models.payments,
attributes: []
}
],
group: ['contracts.id']
})
Ответ 2
Это проблема, которую вы, возможно, захотите выбрать из payments
и присоединяться contracts
, а не наоборот?
Ответ 3
Можете ли вы написать свою функцию как
models.contracts.findAll({
attributes: [
'models.contracts.id'
],
include: [
{
model: models.payments,
attributes: [[models.sequelize.fn('sum', models.sequelize.col('payments.payment_amount')), 'total_cost']]
}
],
group: ['contracts.id']
})
Ответ 4
Try
group: ['contracts.id', 'payments.id']