【问题标题】:Sequelize: Problems with nested include / reverse associationSequelize:嵌套包含/反向关联的问题
【发布时间】:2021-08-05 08:33:35
【问题描述】:

我对 JS 和 Sequelize 还很陌生,现在在查询以下结构时遇到了问题。也许我在这里完全错过了一些基本点。非常感谢您的帮助。

版本:

  • 节点:15.13.0
  • 续集:6.6.2
  • postgres:13.3
  • pg: 8.6.0
  • pg-hstore: 2.3.3

结构

航班始终属于一个用户。不同的用户可以为一个航班创建 cmets。

目标

当我通过它的 ID 选择一个航班时,我想包括用户的姓名,并且我想包括该航班的所有 cmets 以及创建评论的用户的姓名。

问题

我可以将评论添加到航班中。但我无法实现其他目标。 当我运行时:
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 调用的不是 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;

【问题讨论】:

    标签: node.js postgresql sequelize.js


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 谢谢。这行得通。但也有一个缺点。您不能再通过简单的要求将任何模型导入任何其他文件。您需要导入您的数据库对象并通过其密钥访问模型。 const User = require("../model/User") --> const User = require("../config/db)["User"] 有了这个 VSCode 也无法将模型识别为 Sequelize 模型类,并且不会提供任何有关方法等的文档。
      • 不,您仍然可以轻松导入模型,使用 const {User} = require("../models") 完成。
      猜你喜欢
      • 2021-05-01
      • 1970-01-01
      • 2015-10-07
      • 1970-01-01
      • 2017-08-27
      • 2021-02-09
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      相关资源
      最近更新 更多