Sequelize:嵌套包含/反向关联的问题

Sequelize: Problems with nested include / reverse association

我是 JS 和 Sequelize 的新手,现在在查询以下结构时遇到问题。也许我在这里完全遗漏了一些基本点。非常感谢您的帮助。

版本:

结构

一个航班始终属于一个用户。不同的用户可以对一个航班创建评论。

目标

当我 select 一个航班的 ID 时,我想包含用户的姓名,并且我想包含对该航班的所有评论以及创建评论的用户的姓名。

问题

我可以将评论包含在航班中。但我无法实现其他目标。 当我运行:
await Flight.findOne({
      where: { id: flightId },
      include: [
        {
          model: User,
          as: "user",
          attributes: ["id", "name"],
        },
        {
           model: FlightComment,
           as: "comments",
        },
      ],
    });

我会得到错误

SequelizeEagerLoadingError: User is not associated to Flight!

这是可以理解的。所以我尝试将反向关联添加到Flight。

Flight.belongsTo(User)

之后我会得到错误

Flight.belongsTo called with something that's not a subclass of Sequelize.Model

当我在 FlightComment 中定义一个 userId 列时:

  userId: {
    type: DataTypes.UUID,
    references: {
      model: User,
      key: "id",
    },
  },

我在数据库同步过程中会出现以下错误

Executing (default): DROP TABLE IF EXISTS "FlightComments" CASCADE;
TypeError: Cannot read property 'replace' of undefined

我读到您需要在一个文件中定义所有模型,但由于有许多不同的模型,我想将它们分开。

我也没有在官方文档中找到任何建议。

模型文件

我为每个模型创建了一个自己的文件(会有很多不同的模型,所以最好把它们分开)。

飞行文件:

const Flight = db.sequelize.define("Flight", {
  //Many beautiful attributes
});

Flight.hasMany(FlightComment, {
  as: "comments",
  foreignKey: {
    name: "flightId",
    allowNull: false,
  },
  onDelete: "CASCADE",
  hooks: true,
});

//Another association

module.exports = Flight;

FlightComment 文件:

const FlightComment = db.sequelize.define("FlightComment", {
  id: {
    type: Sequelize.UUID,
    defaultValue: Sequelize.UUIDV4,
    allowNull: false,
    primaryKey: true,
  },

  message: {
    type: DataTypes.STRING,
    allowNull: false,
  },
});

module.exports = FlightComment;

用户文件:

const User = db.sequelize.define(
  "User",
  {
    id: {
      type: Sequelize.UUID,
      defaultValue: Sequelize.UUIDV4,
      allowNull: false,
      primaryKey: true,
    },
    name: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true, 
    },
    //Many more attributes
  },
);

User.hasMany(Flight, {
  as: "flights",
  foreignKey: {
    name: "userId",
    allowNull: false,
  },
});

User.hasMany(FlightComment, {
  as: "comments",
  foreignKey: {
    name: "userId",
    allowNull: false,
  },
  onDelete: "CASCADE",
  hooks: true,
});

module.exports = User;

最后,我在一个文件中定义了所有依赖于另一个模型的模型。 这不是我正在寻找的解决方案,但它有效...

您可以通过编程方式初始化数据库及其关联(使用与模型位于同一文件夹中的文件),例如:

'use strict'
 
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const config = {
  "username": "root",
  "password": "YOUR ROOT PASSWORD HERE",
  "database": "YOUR DATABASE NAME HERE",
  "dialect": "postgres"
}
const db = {}
 
let sequelize = new Sequelize(config.database, config.username, config.password, config);
 
fs.readdirSync(__dirname)
  .filter(file => {
    return (file.indexOf('.') !== 0)
    && (file !== basename)
    && (file.slice(-3) === '.js');
  })
  .forEach(file => {
    const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
    db[model.name] = model;
  });
 
Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});
 
db.sequelize = sequelize;
db.Sequelize = Sequelize;
 
module.exports = db;

有了这个,你需要像这样声明你的模型文件:

module.exports = Flight = (sequelize, DataTypes) => {
    const Flight = sequelize.define('Flight', {
        //Many beautiful attributes
    })

    Flight.associate = models => {
        Flight.hasMany(models.FlightComment, { 
            as: 'comments',
            foreignKey: {
                name: "flightId",
                allowNull: false,
            },
            onDelete: "CASCADE",
            hooks: true
        })
        Flight.belongsTo(models.User, {
            as: 'flight',
            foreignKey: {
                name: "flightId",
                allowNull: false,
            }
        })
    }

    return Flight
}