来自关联 fooInstance.getBars() 的 sequelize 方法返回错误值

sequelize methods from association fooInstance.getBars() returning a wrong value

我有 2 个模型通过另一个模型具有多对多关联。默认情况下,Sequelize 会为这两个模型创建实例方法,您可能都知道 (https://sequelize.org/master/manual/assocs.html#special-methods-mixins-added-to-instances)。

我的问题是 fooInstance.getBars() 方法和 fooInstance.countBars() 都 return 错误的记录数。

数据库是使用 sequelize 迁移文件设置的。

下面是3个模型。

module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define(
    "User",
    {
      firstName: DataTypes.STRING
    },
    {}
  );
  User.associate = function(models) {
    // associations can be defined here
    User.belongsToMany(models.Week, {
      through: models.Roster,
      foreignKey: {
        name: "weekId"
      }
    });
  };
  return User;
};

"use strict";
module.exports = (sequelize, DataTypes) => {
  const Week = sequelize.define(
    "Week",
    {
      date: {
        type: DataTypes.DATE,
        allowNull: false,
        unique: true
      }
    },
    {}
  );
  Week.associate = function(models) {
    // associations can be defined here
    Week.belongsToMany(models.User, {
      through: models.Roster,
      foreignKey: {
        name: "userId",
        allowNull: true
      }
    });
  };
  return Week;
};

"use strict";
module.exports = (sequelize, DataTypes) => {
  const Roster = sequelize.define(
    "Roster",
    {
      weekId: {
        type: DataTypes.INTEGER,
        allowNull: false,
        unique: false
      },
      userId: {
        type: DataTypes.INTEGER,
        allowNull: true,
        unique: false
      }
    },
    {}
  );
  Roster.associate = function(models) {
    // associations can be defined here
  };
  return Roster;
};


在我测试这些方法之前,我在几周内创建了 1 条记录,在用户中创建了 5 条记录,然后我在花名册中使用 5 Roster.create() 创建了 5 个关联。

当我像这样 await Week.getUsers() 在我的路由文件中执行查询时,它不是 return 在一个数组中输入 5 个用户,而是 return 在一个数组中输入 1 个。同样,await Week.countUsers() 代码 returned 1 而不是 5。

请帮忙!

如果我遗漏了任何重要信息,请告诉我。

谢谢!

docs 所说:

When an association is defined between two models, the instances of those models gain special methods to interact with their associated counterparts.

您正试图在模型 class 上调用这些特殊方法。这是一个工作示例:

import { sequelize } from '../../db';
import { Model, DataTypes, BelongsToManyGetAssociationsMixin, BelongsToManyCountAssociationsMixin } from 'sequelize';

class User extends Model {}
User.init(
  {
    firstName: DataTypes.STRING,
  },
  { sequelize, modelName: 'User' },
);

class Week extends Model {
  public getUsers!: BelongsToManyGetAssociationsMixin<User>;
  public countUsers!: BelongsToManyCountAssociationsMixin;
}
Week.init(
  {
    date: {
      type: DataTypes.DATE,
      allowNull: false,
      unique: true,
    },
  },
  { sequelize, modelName: 'Week' },
);

class Roster extends Model {}
Roster.init(
  {
    weekId: {
      type: DataTypes.INTEGER,
      allowNull: false,
      unique: false,
    },
    userId: {
      type: DataTypes.INTEGER,
      allowNull: true,
      unique: false,
    },
  },
  { sequelize, modelName: 'Roster' },
);

User.belongsToMany(Week, { through: Roster, foreignKey: { name: 'weekId' } });
Week.belongsToMany(User, { through: Roster, foreignKey: { name: 'userId', allowNull: true } });

(async function test() {
  try {
    // create tables
    await sequelize.sync({ force: true });
    // seed
    const week = await Week.create(
      {
        date: new Date(),
        Users: [
          { firstName: 'james' },
          { firstName: 'elsa' },
          { firstName: 'tim' },
          { firstName: 'lee' },
          { firstName: 'jasmine' },
        ],
      },
      { include: [User] },
    );
    // test
    const count = await week.countUsers();
    console.log('count:', count);
    const users = await week.getUsers();
    console.log('users count:', users.length);
  } catch (error) {
    console.log(error);
  } finally {
    await sequelize.close();
  }
})();

执行结果:

Executing (default): DROP TABLE IF EXISTS "Roster" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Week" CASCADE;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "User" ("id"   SERIAL , "firstName" VARCHAR(255), PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'User' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "Week" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Week" ("id"   SERIAL , "date" TIMESTAMP WITH TIME ZONE NOT NULL UNIQUE, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Week' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "Roster" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Roster" ("weekId" INTEGER NOT NULL  REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE, "userId" INTEGER  REFERENCES "Week" ("id") ON DELETE CASCADE ON UPDATE CASCADE, UNIQUE ("weekId", "userId"), PRIMARY KEY ("weekId","userId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Roster' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "Week" ("id","date") VALUES (DEFAULT,) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,) RETURNING *;
Executing (default): INSERT INTO "User" ("id","firstName") VALUES (DEFAULT,) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES (,) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES (,) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES (,) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES (,) RETURNING *;
Executing (default): INSERT INTO "Roster" ("weekId","userId") VALUES (,) RETURNING *;
Executing (default): SELECT COUNT("User"."id") AS "count" FROM "User" AS "User" INNER JOIN "Roster" AS "Roster" ON "User"."id" = "Roster"."weekId" AND "Roster"."userId" = 1;
count: 5
Executing (default): SELECT "User"."id", "User"."firstName", "Roster"."weekId" AS "Roster.weekId", "Roster"."userId" AS "Roster.userId" FROM "User" AS "User" INNER JOIN "Roster" AS "Roster" ON "User"."id" = "Roster"."weekId" AND "Roster"."userId" = 1;
users count: 5

检查数据库:

node-sequelize-examples=# select * from "User";
 id | firstName
----+-----------
  1 | james
  2 | elsa
  3 | tim
  4 | lee
  5 | jasmine
(5 rows)

node-sequelize-examples=# select * from "Week";
 id |           date
----+---------------------------
  1 | 2020-04-14 01:56:56.55+00
(1 row)

node-sequelize-examples=# select * from "Roster";
 weekId | userId
--------+--------
      1 |      1
      2 |      1
      3 |      1
      4 |      1
      5 |      1
(5 rows)

依赖版本:"sequelize": "^5.21.3"postgres:9.6

源代码:https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/Whosebug/60805725