web-dev-qa-db-ja.com

Sequelizeでグループ化と結合を使用する

PostgreSQLデータベースには、契約と支払いの2つのテーブルがあります。 1つの契約で複数の支払いが行われます。

次の2つのモデルがあります。

 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リクエストが有効になる方法がわかりません。

24
syldor

この問題はSequelize 3.0.1で修正されました。含まれるモデルの主キーは、

attributes: []

集約はメインモデルで行う必要があります( this github issue の情報)。

したがって、私のユースケースでは、コードは次のようになります

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

試して

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

問題は、paymentsから選択してcontractsに参加するのではなく、逆にしたいですか?

1
swifty

あなたの関数を

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