【问题标题】:Sequelize one-to-many association errorsSequelize 一对多关联错误
【发布时间】:2018-06-14 21:25:26
【问题描述】:

我目前正在开发一个使用 SequelizeJS 和 PostgreDB 的新 API。我通常使用 MongoDB,并且在使关联基于特定列(而不是标准 id)工作时遇到了一些麻烦。我想减少在常见操作中进行的数据库调用次数。

我有 3 个表,命名如下:站点、建筑物、区域。
- 站点有许多建筑物(站点:参考 建筑物:siteReference)
- 建筑物有很多区域(建筑物:参考 区域:buildingReference)
- 建筑物属于站点
- 区域属于建筑物

我已尽我所能遵循 Sequelize 文档(发现这些示例有点难以理解),并相信以下内容会起作用(目前只是站点建筑物):

Sites.hasMany(Buildings, { as: 'relatedBuildings', targetKey: 'siteReference'});
Buildings.belongsTo(Sites, { as: 'parentSite', sourceKey: 'reference'});

// Query function
return mainDB.Sites
    .findAll({
        raw: true,
        include: [{
            model: mainDB.Buildings,
            as: 'relatedBuildings'
        }]
    })
    .then(dbRes => { console.log(dbRes));
    .catch(error => {console.log('ERROR', error.message)})

但是,当我运行上述代码时,我收到以下错误:

First Error: relation "Sites" does not exist (note: the associations are stopping this table from being created)

Second Error: 
"status": 409,
            "message": "A database error occurred. Further details attached.",
            "value": {
                "name": "SequelizeDatabaseError",
                "parent": {
                    "name": "error",
                    "length": 110,
                    "severity": "ERROR",
                    "code": "42P01",
                    "position": "1678",
                    "file": "parse_relation.c",
                    "line": "1160",
                    "routine": "parserOpenTable",
                    "sql": "SELECT \"Sites\".\"id\", \"Sites\".\"reference\", \"Sites\".\"name\", \"Sites\".\"description\", \"Sites\".\"addressLine1\", \"Sites\".\"addressLine2\", \"Sites\".\"city\", \"Sites\".\"county\", \"Sites\".\"postcode\", \"Sites\".\"country\", \"Sites\".\"lat\", \"Sites\".\"long\", \"Sites\".\"type\", \"Sites\".\"companyReference\", \"Sites\".\"namedContactReference\", \"Sites\".\"status\", \"Sites\".\"created_at\", \"Sites\".\"updated_at\", \"relatedBuildings\".\"id\" AS \"relatedBuildings.id\", \"relatedBuildings\".\"reference\" AS \"relatedBuildings.reference\", \"relatedBuildings\".\"name\" AS \"relatedBuildings.name\", \"relatedBuildings\".\"description\" AS \"relatedBuildings.description\", \"relatedBuildings\".\"addressLine1\" AS \"relatedBuildings.addressLine1\", \"relatedBuildings\".\"addressLine2\" AS \"relatedBuildings.addressLine2\", \"relatedBuildings\".\"city\" AS \"relatedBuildings.city\", \"relatedBuildings\".\"county\" AS \"relatedBuildings.county\", \"relatedBuildings\".\"postcode\" AS \"relatedBuildings.postcode\", \"relatedBuildings\".\"country\" AS \"relatedBuildings.country\", \"relatedBuildings\".\"lat\" AS \"relatedBuildings.lat\", \"relatedBuildings\".\"long\" AS \"relatedBuildings.long\", \"relatedBuildings\".\"type\" AS \"relatedBuildings.type\", \"relatedBuildings\".\"siteReference\" AS \"relatedBuildings.siteReference\", \"relatedBuildings\".\"namedContactReference\" AS \"relatedBuildings.namedContactReference\", \"relatedBuildings\".\"status\" AS \"relatedBuildings.status\", \"relatedBuildings\".\"created_at\" AS \"relatedBuildings.created_at\", \"relatedBuildings\".\"updated_at\" AS \"relatedBuildings.updated_at\", \"relatedBuildings\".\"site_id\" AS \"relatedBuildings.site_id\", \"relatedBuildings\".\"related_buildings_id\" AS \"relatedBuildings.related_buildings_id\" FROM \"Sites\" AS \"Sites\" LEFT OUTER JOIN \"Buildings\" AS \"relatedBuildings\" ON \"Sites\".\"id\" = \"relatedBuildings\".\"site_id\";"
                },
                "original": {
                    "name": "error",
                    "length": 110,
                    "severity": "ERROR",
                    "code": "42P01",
                    "position": "1678",
                    "file": "parse_relation.c",
                    "line": "1160",
                    "routine": "parserOpenTable",
                    "sql": "SELECT \"Sites\".\"id\", \"Sites\".\"reference\", \"Sites\".\"name\", \"Sites\".\"description\", \"Sites\".\"addressLine1\", \"Sites\".\"addressLine2\", \"Sites\".\"city\", \"Sites\".\"county\", \"Sites\".\"postcode\", \"Sites\".\"country\", \"Sites\".\"lat\", \"Sites\".\"long\", \"Sites\".\"type\", \"Sites\".\"companyReference\", \"Sites\".\"namedContactReference\", \"Sites\".\"status\", \"Sites\".\"created_at\", \"Sites\".\"updated_at\", \"relatedBuildings\".\"id\" AS \"relatedBuildings.id\", \"relatedBuildings\".\"reference\" AS \"relatedBuildings.reference\", \"relatedBuildings\".\"name\" AS \"relatedBuildings.name\", \"relatedBuildings\".\"description\" AS \"relatedBuildings.description\", \"relatedBuildings\".\"addressLine1\" AS \"relatedBuildings.addressLine1\", \"relatedBuildings\".\"addressLine2\" AS \"relatedBuildings.addressLine2\", \"relatedBuildings\".\"city\" AS \"relatedBuildings.city\", \"relatedBuildings\".\"county\" AS \"relatedBuildings.county\", \"relatedBuildings\".\"postcode\" AS \"relatedBuildings.postcode\", \"relatedBuildings\".\"country\" AS \"relatedBuildings.country\", \"relatedBuildings\".\"lat\" AS \"relatedBuildings.lat\", \"relatedBuildings\".\"long\" AS \"relatedBuildings.long\", \"relatedBuildings\".\"type\" AS \"relatedBuildings.type\", \"relatedBuildings\".\"siteReference\" AS \"relatedBuildings.siteReference\", \"relatedBuildings\".\"namedContactReference\" AS \"relatedBuildings.namedContactReference\", \"relatedBuildings\".\"status\" AS \"relatedBuildings.status\", \"relatedBuildings\".\"created_at\" AS \"relatedBuildings.created_at\", \"relatedBuildings\".\"updated_at\" AS \"relatedBuildings.updated_at\", \"relatedBuildings\".\"site_id\" AS \"relatedBuildings.site_id\", \"relatedBuildings\".\"related_buildings_id\" AS \"relatedBuildings.related_buildings_id\" FROM \"Sites\" AS \"Sites\" LEFT OUTER JOIN \"Buildings\" AS \"relatedBuildings\" ON \"Sites\".\"id\" = \"relatedBuildings\".\"site_id\";"
                },
                "sql": "SELECT \"Sites\".\"id\", \"Sites\".\"reference\", \"Sites\".\"name\", \"Sites\".\"description\", \"Sites\".\"addressLine1\", \"Sites\".\"addressLine2\", \"Sites\".\"city\", \"Sites\".\"county\", \"Sites\".\"postcode\", \"Sites\".\"country\", \"Sites\".\"lat\", \"Sites\".\"long\", \"Sites\".\"type\", \"Sites\".\"companyReference\", \"Sites\".\"namedContactReference\", \"Sites\".\"status\", \"Sites\".\"created_at\", \"Sites\".\"updated_at\", \"relatedBuildings\".\"id\" AS \"relatedBuildings.id\", \"relatedBuildings\".\"reference\" AS \"relatedBuildings.reference\", \"relatedBuildings\".\"name\" AS \"relatedBuildings.name\", \"relatedBuildings\".\"description\" AS \"relatedBuildings.description\", \"relatedBuildings\".\"addressLine1\" AS \"relatedBuildings.addressLine1\", \"relatedBuildings\".\"addressLine2\" AS \"relatedBuildings.addressLine2\", \"relatedBuildings\".\"city\" AS \"relatedBuildings.city\", \"relatedBuildings\".\"county\" AS \"relatedBuildings.county\", \"relatedBuildings\".\"postcode\" AS \"relatedBuildings.postcode\", \"relatedBuildings\".\"country\" AS \"relatedBuildings.country\", \"relatedBuildings\".\"lat\" AS \"relatedBuildings.lat\", \"relatedBuildings\".\"long\" AS \"relatedBuildings.long\", \"relatedBuildings\".\"type\" AS \"relatedBuildings.type\", \"relatedBuildings\".\"siteReference\" AS \"relatedBuildings.siteReference\", \"relatedBuildings\".\"namedContactReference\" AS \"relatedBuildings.namedContactReference\", \"relatedBuildings\".\"status\" AS \"relatedBuildings.status\", \"relatedBuildings\".\"created_at\" AS \"relatedBuildings.created_at\", \"relatedBuildings\".\"updated_at\" AS \"relatedBuildings.updated_at\", \"relatedBuildings\".\"site_id\" AS \"relatedBuildings.site_id\", \"relatedBuildings\".\"related_buildings_id\" AS \"relatedBuildings.related_buildings_id\" FROM \"Sites\" AS \"Sites\" LEFT OUTER JOIN \"Buildings\" AS \"relatedBuildings\" ON \"Sites\".\"id\" = \"relatedBuildings\".\"site_id\";"
            }

当我在我的 Sites 表上运行 FindAll() 时,最终我的目标是获得如下输出:

Site
- Building
- - Area
- - Area
- Building
- - Area
- Building
- - Area
- - Area
- - Area
Site
- Building
- - Area
- - Area
- Building
- - Area
- - Area
Site
- Building
- - Area
- - Area

我哪里错了?

更新 - 这是我的模型(注意我在别处正式定义它们)

网站

const Sites = {
    name: 'Sites',
    schema: {
        id: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: false
        },
        reference: {
            type: DataTypes.STRING(100),
            unique: true,
            allowNull: false
        },
        name: {
            type: DataTypes.STRING,
            allowNull: false
        },
        description: {
            type: DataTypes.STRING(512),
            allowNull: true
        },
        addressLine1: {
            type: DataTypes.STRING,
            allowNull: false
        },
        addressLine2: {
            type: DataTypes.STRING,
            allowNull: false
        },
        city: {
            type: DataTypes.STRING,
            allowNull: false
        },
        county: {
            type: DataTypes.STRING,
            allowNull: false
        },
        postcode: {
            type: DataTypes.STRING,
            allowNull: false
        },
        country: {
            type: DataTypes.STRING,
            allowNull: false
        },
        lat: {
            type: DataTypes.STRING,
            allowNull: false
        },
        long: {
            type: DataTypes.STRING,
            allowNull: false
        },
        type: {
            type: DataTypes.STRING,
            allowNull: false
        },
        companyReference: {
            type: DataTypes.STRING(100),
            allowNull: false
        },
        namedContactReference: {
            type: DataTypes.STRING(100),
            allowNull: true
        },
        status: {
            type: DataTypes.STRING(20),
            allowNull: false
        }
    },
    options: {
        underscored: true
    }
};

export default Sites;

建筑物

const Buildings = {
    name: 'Buildings',
    schema: {
        id: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: false
        },
        reference: {
            type: DataTypes.STRING(100),
            unique: true,
            allowNull: false
        },
        name: {
            type: DataTypes.STRING,
            allowNull: false
        },
        description: {
            type: DataTypes.STRING(256),
            unique: false,
            allowNull: true
        },
        addressLine1: {
            type: DataTypes.STRING,
            allowNull: false
        },
        addressLine2: {
            type: DataTypes.STRING,
            allowNull: false
        },
        city: {
            type: DataTypes.STRING,
            allowNull: false
        },
        county: {
            type: DataTypes.STRING,
            allowNull: false
        },
        postcode: {
            type: DataTypes.STRING,
            allowNull: false
        },
        country: {
            type: DataTypes.STRING,
            allowNull: false
        },
        lat: {
            type: DataTypes.STRING,
            allowNull: false
        },
        long: {
            type: DataTypes.STRING,
            allowNull: false
        },
        type: {
            type: DataTypes.STRING,
            allowNull: false
        },
        siteReference: {
            type: DataTypes.STRING(100),
            allowNull: false
        },
        namedContactReference: {
            type: DataTypes.STRING(100),
            allowNull: true
        },
        status: {
            type: DataTypes.STRING(20),
            allowNull: false
        }
    },
    options: { underscored: true }
};
export default Buildings;

区域

const Areas = {
    name: 'Areas',
    schema: {
        id: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: false
        },
        reference: {
            type: DataTypes.STRING(100),
            unique: true,
            allowNull: false
        },
        buildingReference: {
            type: DataTypes.STRING(100),
            unique: false,
            allowNull: false
        },
        panelReference: {
            type: DataTypes.STRING(100),
            unique: false,
            allowNull: false
        },
        name: {
            type: DataTypes.STRING(128),
            unique: false,
            allowNull: false
        },
        description: {
            type: DataTypes.STRING(512),
            allowNull: true
        },
        drawingReference: {
            type: DataTypes.STRING(100),
            unique: false,
            allowNull: false
        },
        status: {
            type: DataTypes.STRING(10),
            allowNull: false
        }
    },
    options: { underscored: true }
};
export default Areas;

【问题讨论】:

  • 你能粘贴完整的模型文件吗,有很多地方可能会出错。表是否存在或者你是否在迁移时运行同步
  • @KevalGohil 我一定会在今天晚些时候回到我的电脑前发布它们。目前我有 force:true 同步,因为我正在使用种子数据预填充测试内容。一切正常,直到我开始在关联中编码!
  • @KevalGohil 模型添加

标签: sql node.js postgresql sequelize.js


【解决方案1】:

您是否在模型中设置了关联?

请参阅部分的Sequelize docs

示例

如果我正确理解您的问题,您想建立一个多对多关系,即 n:m。

使用,您可以通过在两个模型上设置关系来做到这一点

belongsToMany(Model,{through: 'tableNameYouWant'});


// In Your Site Model
Sites.belongsToMany(Buildings, {through: 'SiteBuildings'});

// In your Building Model
Buildings.belongsToMany(Sites, {through: 'SiteBuildings'});

// In your Area Model
Areas.belongsTo(Buildings)

如果这有助于解决您的问题,请告诉我!

【讨论】:

  • 我在定义每个模型时进行关联。我定义我的模式,将其导入模型定义,然后一次定义它们。然后我在强制同步之前运行一个包含所有这些关联的函数。正如我在 Postico 中看到的那样,它们正在被应用。也许我会放弃这个实现并使用文档中描述的那个。
  • 所以我将 through: 'SiteBuildings' 更改为我的表名,但是我得到:'SequelizeAssociationError: You have used the alias Buildings in two separate associations。别名关联必须具有唯一别名。'。我也尝试了包含 sourceKey 和 targetKey,但没有进一步的运气。
  • @user5156141 好吧,所以如果你有一个 AssociationError 它基本上意味着:你已经在其他地方使用了 as 'Buildings' Association。这在 Sequelize 中是不可能的。你能把我加到你的 github 项目中吗?如果你愿意,我可以看看。
  • 除了我的数据库表之外,我没有故意命名任何建筑物。我有一个 HasMany 与包含建筑物的站点一起工作。只需要弄清楚如何获得这些建筑物的区域以及每个站点的公司!
  • 我无法将您添加到主项目。我会分叉它并删除所有敏感的东西,我可以将你添加到其中。将尽快做到这一点。到目前为止,我已经设法让 hasMany 工作(虽然别名不起作用),但没有 BelongsTo、belongsToMany 或 hasOne。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-11
  • 1970-01-01
  • 1970-01-01
  • 2016-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多