Javascript sequelize查询:响应为我提供了不存在的列

Javascript sequelize查询:响应为我提供了不存在的列,javascript,postgresql,reactjs,sequelize.js,Javascript,Postgresql,Reactjs,Sequelize.js,我正在使用ORM sequelize在express.js中创建小型REST API 我遇到了以下问题: 我想让所有客户都带上他们的照片。我有两个表Customer和CustomerPhoto,它们的关系是1:1(因此PrimaryKey也是外键) 问题是sequelize想要创建一个不存在列的联接CustomerPhotoCustomerPhotoID。我怎么知道?当我只想从customer表中获取所有行时,我遇到了类似的问题。我用属性来“解决”它,只检索到我真正需要的行 Customer.j

我正在使用ORM sequelize在express.js中创建小型REST API

我遇到了以下问题: 我想让所有客户都带上他们的照片。我有两个表Customer和CustomerPhoto,它们的关系是1:1(因此PrimaryKey也是外键)

问题是sequelize想要创建一个不存在列的联接CustomerPhotoCustomerPhotoID。我怎么知道?当我只想从customer表中获取所有行时,我遇到了类似的问题。我用属性来“解决”它,只检索到我真正需要的行

Customer.js模型:

module.exports = (sequelize, DataTypes) => {
  const Customer = sequelize.define('Customer', {
    customerID: {
      type: DataTypes.INTEGER,
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
    },
    firstname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    lastname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    phone: {
      type: DataTypes.STRING,
    },
    email: {
      type: DataTypes.STRING,
      unique: true,
      validate: {
        isEmail: true,
      },
    },
  }, {
    classMethods: {
      associate(models) {
        Customer.hasOne(models.CustomerPhoto, { onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
  });
  return Customer;
};
module.exports = (sequelize, DataTypes) => {
  const CustomerPhoto = sequelize.define('CustomerPhoto', {
    customerPhotoID: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER,
      references: {
        model: 'Customer',
        key: 'customerID',
        deferrable: sequelize.Deferrable.INITIALLY_IMMEDIATE,
      },
    },
    filename: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 15],
      },
    },
    filetype: {
      type: DataTypes.BLOB,
    },
  }, {
    classMethods: {
      associate(models) {
        CustomerPhoto.hasOne(models.Customer, { onDelete: 'cascade', hooks: 'true' })
      },
    },
  })
  return CustomerPhoto
}


export function fetchCustomers(req, res) {
  models.Customer.findAll({
    attributes: ['firstname', 'lastname', 'phone', 'email', 'filetype'],
    include: [{
      model: models.CustomerPhoto,
      // if true inner join otherwise left join
      required: true,
    }],
  }).then((result) => {
    res.json(result)
  }).catch((error) => {
    res.send(error)
  })
}
CustomerPhoto.js模型:

module.exports = (sequelize, DataTypes) => {
  const Customer = sequelize.define('Customer', {
    customerID: {
      type: DataTypes.INTEGER,
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
    },
    firstname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    lastname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    phone: {
      type: DataTypes.STRING,
    },
    email: {
      type: DataTypes.STRING,
      unique: true,
      validate: {
        isEmail: true,
      },
    },
  }, {
    classMethods: {
      associate(models) {
        Customer.hasOne(models.CustomerPhoto, { onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
  });
  return Customer;
};
module.exports = (sequelize, DataTypes) => {
  const CustomerPhoto = sequelize.define('CustomerPhoto', {
    customerPhotoID: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER,
      references: {
        model: 'Customer',
        key: 'customerID',
        deferrable: sequelize.Deferrable.INITIALLY_IMMEDIATE,
      },
    },
    filename: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 15],
      },
    },
    filetype: {
      type: DataTypes.BLOB,
    },
  }, {
    classMethods: {
      associate(models) {
        CustomerPhoto.hasOne(models.Customer, { onDelete: 'cascade', hooks: 'true' })
      },
    },
  })
  return CustomerPhoto
}


export function fetchCustomers(req, res) {
  models.Customer.findAll({
    attributes: ['firstname', 'lastname', 'phone', 'email', 'filetype'],
    include: [{
      model: models.CustomerPhoto,
      // if true inner join otherwise left join
      required: true,
    }],
  }).then((result) => {
    res.json(result)
  }).catch((error) => {
    res.send(error)
  })
}
我在《邮递员》中得到以下回应:

{
  "name": "SequelizeDatabaseError",
  "message": "column \"CustomerPhotoCustomerPhotoID\" does not exist",
  "parent": {
    "name": "error",
    "length": 128,
    "severity": "ERROR",
    "code": "42703",
    "position": "91",
    "file": "parse_relation.c",
    "line": "3183",
    "routine": "errorMissingColumn",
    "sql": "SELECT \"customerID\", \"firstname\", \"lastname\", \"phone\", \"email\", \"createdAt\", \"updatedAt\", \"CustomerPhotoCustomerPhotoID\", \"OrderOrderID\" FROM \"Customers\" AS \"Customer\" WHERE \"Customer\".\"customerID\" = '1';"
  },
  "original": {
    "name": "error",
    "length": 128,
    "severity": "ERROR",
    "code": "42703",
    "position": "91",
    "file": "parse_relation.c",
    "line": "3183",
    "routine": "errorMissingColumn",
    "sql": "SELECT \"customerID\", \"firstname\", \"lastname\", \"phone\", \"email\", \"createdAt\", \"updatedAt\", \"CustomerPhotoCustomerPhotoID\", \"OrderOrderID\" FROM \"Customers\" AS \"Customer\" WHERE \"Customer\".\"customerID\" = '1';"
  },
  "sql": "SELECT \"customerID\", \"firstname\", \"lastname\", \"phone\", \"email\", \"createdAt\", \"updatedAt\", \"CustomerPhotoCustomerPhotoID\", \"OrderOrderID\" FROM \"Customers\" AS \"Customer\" WHERE \"Customer\".\"customerID\" = '1';"
}

好的,这里有一些东西。首先,您不需要在两个模型上声明1:1关系。只需在一个模型上执行,这取决于您如何执行

您可以使用belongsTohasOne,两者都用于1:1关系,但工作方式不同

belong在源模型上创建外键,在目标模型上创建外键。Sequelize甚至建议在大多数情况下使用belongsTo。是链接

“尽管它被称为哈松协会,但对于大多数1:1关系而言 您通常需要BelongsTo关联,因为BelongsTo将添加 hasOne将添加到目标的源上的foreignKey。“

现在对于db模式,您真的需要CustomerPhoto的主键必须是引用客户id模型的外键吗?我建议您对CustomerPhotos使用常规主键,只需在Custommer模型上进行引用,该模型将创建具有id关联的列

classMethods: {
      associate(models) {
        Customer.belongsTo(models.CustomerPhoto, { as : 'CustomerPhotoID', onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
在您的查询呼叫中,包括以下内容:

models.Customer.findAll({
    attributes: ['firstname', 'lastname', 'phone', 'email', 'filetype'],
    include: [{
      model: models.CustomerPhoto,
      as : 'CustomerPhotoID',
      // if true inner join otherwise left join
      required: true,
    }],
  }).then

“as”参数将帮助sequelize找到某种意义上的关系。

好的,这里有一些东西。首先,您不需要在两个模型上声明1:1关系。只需在一个模型上执行,这取决于您如何执行

您可以使用belongsTohasOne,两者都用于1:1关系,但工作方式不同

belong在源模型上创建外键,在目标模型上创建外键。Sequelize甚至建议在大多数情况下使用belongsTo。是链接

“尽管它被称为哈松协会,但对于大多数1:1关系而言 您通常需要BelongsTo关联,因为BelongsTo将添加 hasOne将添加到目标的源上的foreignKey。“

现在对于db模式,您真的需要CustomerPhoto的主键必须是引用客户id模型的外键吗?我建议您对CustomerPhotos使用常规主键,只需在Custommer模型上进行引用,该模型将创建具有id关联的列

classMethods: {
      associate(models) {
        Customer.belongsTo(models.CustomerPhoto, { as : 'CustomerPhotoID', onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
在您的查询呼叫中,包括以下内容:

models.Customer.findAll({
    attributes: ['firstname', 'lastname', 'phone', 'email', 'filetype'],
    include: [{
      model: models.CustomerPhoto,
      as : 'CustomerPhotoID',
      // if true inner join otherwise left join
      required: true,
    }],
  }).then

“as”参数将帮助sequelize找到某种意义上的关系。

@Ellebkey。谢谢你的回答。是的,在你发帖之前我意识到我在hasOne协会犯了这个错误。我修改了代码,改为使用belongTo。我还在客户表中创建了外键,但这并没有解决我的问题

问题出在外键的定义上。Sequelize默认创建FK,但我自己定义了它,没有关联编写

classMethods: {
      associate(models) {
        Customer.belongsTo(models.CustomerPhoto, { as : 'CustomerPhotoID', onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
在下面的示例中,我决定在customer表中将customerPhotoID创建为FK。之后我把它加入了协会而且有效
module.exports = (sequelize, DataTypes) => {
  const Customer = sequelize.define('Customer', {
    customerID: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER,
    },
    customerPhotoID: {
      type: DataTypes.INTEGER,
      references: {
        model: 'Customers',
        key: 'customerID',
        deferrable: sequelize.Deferrable.INITIALLY_IMMEDIATE,
      },
    },
    firstname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    lastname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    phone: {
      type: DataTypes.STRING,
    },
    email: {
      type: DataTypes.STRING,
      unique: true,
      validate: {
        isEmail: true,
      },
    },
  }, {
    classMethods: {
      associate(models) {
        Customer.belongsTo(models.CustomerPhoto, { foreignKey: 'customerPhotoID', onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
  });
  return Customer;
};

@埃勒布基。谢谢你的回答。是的,在你发帖之前我意识到我在hasOne协会犯了这个错误。我修改了代码,改为使用belongTo。我还在客户表中创建了外键,但这并没有解决我的问题

问题出在外键的定义上。Sequelize默认创建FK,但我自己定义了它,没有关联编写

classMethods: {
      associate(models) {
        Customer.belongsTo(models.CustomerPhoto, { as : 'CustomerPhotoID', onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
在下面的示例中,我决定在customer表中将customerPhotoID创建为FK。之后我把它加入了协会而且有效
module.exports = (sequelize, DataTypes) => {
  const Customer = sequelize.define('Customer', {
    customerID: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER,
    },
    customerPhotoID: {
      type: DataTypes.INTEGER,
      references: {
        model: 'Customers',
        key: 'customerID',
        deferrable: sequelize.Deferrable.INITIALLY_IMMEDIATE,
      },
    },
    firstname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    lastname: {
      type: DataTypes.STRING,
      validate: {
        len: [3, 10],
      },
    },
    phone: {
      type: DataTypes.STRING,
    },
    email: {
      type: DataTypes.STRING,
      unique: true,
      validate: {
        isEmail: true,
      },
    },
  }, {
    classMethods: {
      associate(models) {
        Customer.belongsTo(models.CustomerPhoto, { foreignKey: 'customerPhotoID', onDelete: 'cascade', hooks: 'true' });
        Customer.hasMany(models.Order, { onDelete: 'cascade', hooks: 'true' });
      },
    },
  });
  return Customer;
};