web-dev-qa-db-fra.com

Utilisation de Group By et Join dans Sequelize

J'ai deux tableaux sur une base de données PostgreSQL, des contrats et des paiements. Un contrat comporte plusieurs paiements.

J'ai les deux modèles suivants:

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

Je voudrais résumer tous les paiements effectués pour chaque contrat et j'ai utilisé cette fonction:

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']
})

Mais il génère la requête suivante:

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";

Je ne demande pas de sélectionner paiements.id, car je devrais l'inclure dans mon agrégation ou grouper par fonctions, comme dit dans l'erreur que j'ai:

SequelizeDatabaseError éventuellement non gérée: erreur: la colonne "paiements.id" doit apparaître dans la clause GROUP BY ou être utilisée dans une fonction d'agrégation

Est-ce que j'ai râté quelque chose ? Je suis cette réponse mais même là, je ne comprends pas comment la requête SQL peut être valide.

24
syldor

Ce problème a été corrigé sur Sequelize 3.0.1, la clé primaire des modèles inclus doit être exclue avec

attributes: []

et l'agrégation doit être faite sur le modèle principal (infos dans ce problème github ).

Ainsi pour mon cas d'utilisation, le code est le suivant

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']
})
22
syldor

Essayer

group: ['contracts.id', 'payments.id']
2
Calvintwr

Le problème que vous voudrez peut-être sélectionner parmi payments et rejoindre contracts plutôt que l'inverse?

1
swifty

Pouvez-vous écrire votre fonction comme

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']
})
1
Rahul Bhati