为什么 Sequelize "include / attributes" 不适用于 findAll 和 findOne 请求
Why does Sequelize "include / attributes" won't work with findAll and findOne requests
我正在研究通过 Sequelize 与 MySQL 通信的 API。
我正在处理用户和他们的出版物。这工作得很好,我可以创建与 userId 关联的用户和出版物。但是现在我想获取发布的用户名,而不仅仅是 userId。
所以我使用我的模型 'Users' 和 'Publications' 之间的关联。我已经在我的续集模型和迁移文件中定义了关联,但是当我添加到我的控制器时:
model : User,
attributes: ['firstName']
}],
我收到没有详细信息的错误 400。
如果我只写没有属性的“模型:用户”,它也不起作用,所以我猜它找不到模型用户。
我按照 Sequelize 手册中解释的步骤进行操作,尝试与其他 github 示例进行比较,理论上似乎没问题。我花了两天时间尝试更改字符大小写,我尝试了 sequelize here 提供的许多选项,我删除了所有表格并重新创建了它们,但我现在 运行 在圈子里:-)
在我的迁移文件和模型下面。
感谢您的帮助!
出版物控制器
const models = require('../models'); // importation des modèles sequelize
const Publication = models.publication;
const User = models.user;
exports.getAllPublications = (req, res, next) => {
Publication.findAll({
include: [{
model : User,
attributes: ['firstName']
}],
order: [['createdAt', 'DESC']]
})
.then(
(publications) => {
res.status(200).json(publications);
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};
用户续集模型
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
static associate(models) {
models.User.hasMany(models.Publication)
}
};
User.init({
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN
}, {
sequelize,
modelName: 'User',
});
return User;
};
出版物续集模型
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Publication extends Model {
static associate(models) {
models.Publication.belongsTo(models.User, {
foreignKey: {
allowNull: false,
}
});
}
};
Publication.init({
userId: DataTypes.INTEGER,
title: DataTypes.STRING,
content: DataTypes.STRING
}, {
sequelize,
modelName: 'Publication',
});
return Publication;
};
索引
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
require('dotenv').config() // importation dotenv pour sécuriser passwords
const db = {};
let sequelize;
sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASSWORD, {
host: process.env.DB_HOST,
dialect: process.env.DB_DIALECT
});
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;
db.user = require("./user.js")(sequelize, Sequelize)
db.publication = require("./publication.js")(sequelize, Sequelize)
db.comment = require("./comment.js")(sequelize, Sequelize)
module.exports = db
发布迁移文件
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Publications', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
}
},
title: {
allowNull: false,
type: Sequelize.STRING,
len: [2,50]
},
content: {
allowNull: false,
type: Sequelize.STRING(1234),
len: [2,1000]
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Publications');
}
};
用户创建控制器
exports.signup = (req, res, next) => {
bcrypt.hash(req.body.password, 10) // On crypte le mot de passe (algorithme exécuté 10 fois) / asynchrone
.then(hash => {
console.log(hash)
const newUser = User.create({ // modèle sequelize
lastName : req.body.lastName,
firstName : req.body.firstName,
email: req.body.email,
password: hash, // On enregistre le mdp crypté plutôt que le mdp simple
})
.then((newUser )=> res.status(201).json({ message: 'created' })) // Requête traitée avec succès et création d’un document
.catch(error =>
res.status(400).json({ error })); // Bad Request*/
})
.catch(error => {
console.log("erreur 500")
res.status(500).json({ error })}); // Erreur interne du serveur
};
根据建议更改模型后的新App.js
'use strict'
const express = require('express'); // importation application Express
require('dotenv').config() // importation dotenv pour sécuriser passwords
const mysqlTable = process.env.MYSQLTABLE;
const mysqlUsername = process.env.MYSQLUSERNAME;
const mysqlPassword = process.env.MYSQLPASSWORD;
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
const bodyParser = require('body-parser'); // importation fonction body parser pour extraction objet json de la demande
const cors = require('cors'); // module CORS
const { Sequelize } = require('sequelize'); // importation application Sequelize pour communiquer avec MySQL
const userRoutes = require('./routes/user'); // Importation routeur users
const publicationRoutes = require('./routes/publication'); // Importation routeur posts
const commentRoutes = require('./routes/comment'); // Importation routeur posts
const Publication = require('./models/publication');
const User = require('./models/user')
Publication.belongsTo(User, { Constraints: true, onDelete: 'CASCADE'});
User.hasMany(Publication);
const sequelize = new Sequelize(mysqlTable, mysqlUsername, mysqlPassword, { // Connexion à la base de données mySQL
host : 'localhost',
dialect: 'mysql'
})
const app = express(); // application Express
app.use(bodyParser.json()); // Enregistrement body parser
app.use(cors()); // module CORS
app.use(limiter); // rate limit
app.use((req, res, next) => { // Ajout headers pour résoudre les erreurs CORS
res.setHeader('Access-Control-Allow-Origin', '*'); // accéder à notre API depuis n'importe quelle origine
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization'); // ajouter les headers mentionnés aux requêtes envoyées vers notre API
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS'); // envoyer des requêtes avec les méthodes mentionnées
next();
});
app.use('/api/auth', userRoutes) // Enregistrement routeur users
app.use('/api/publication', publicationRoutes) // Enregistrement routeur publications
app.use('/api/comment', commentRoutes) // Enregistrement routeur publications
module.exports = app;
根据我们交流的意见了解到,问题出在协会的声明上。
我个人不喜欢像你所做的那样定义关联(我没有说它不正确!),我个人喜欢跟随。
我在特定文件下创建了一个Sequelize实例(例如在./util/database.js下):
database.js:
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database_name', 'user_name', 'password', {
dialect: 'mysql',
storage: "./session.mysql",
host: 'localhost'
});
module.exports = sequelize;
我这样定义我的模型:
用户模型:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const User = sequelize.define('user', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
firstName: Sequelize.STRING,
lastName: Sequelize.STRING,
email: Sequelize.STRING,
password: Sequelize.STRING,
isAdmin: Sequelize.BOOLEAN
});
module.exports = User;
出版模式:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const Publication = sequelize.define('publication', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
title: Sequelize.STRING,
content: Sequelize.STRING
});
module.exports = Publication;
然后,我在 app.js 文件中定义关联:
Publication.belongsTo(User, { Constraints: true, onDelete: 'CASCADE'});
User.hasMany(Publication);
为了确保新数据库的模式得到很好的集成,我使用了 sync
方法和 force
属性(只是第一次,那么你应该删除这个属性并只使用同步方法)
// this will run on starting the server
sequelize
.sync({ force: true }) // run it just in the first time after changing the database, this command will re-draw the database
// .sync()
.then(() => app.listen(8080))
.catch(err => console.log(err));
最后,您可以保留您所做的获取数据的操作,也可以这样做:
User.findByPk(userId, {include: ['publications']})
//supposing that you have an instance of a User (user)
user.getPublications({})
user.getPublications({where: { id: publicationId }})
我正在研究通过 Sequelize 与 MySQL 通信的 API。 我正在处理用户和他们的出版物。这工作得很好,我可以创建与 userId 关联的用户和出版物。但是现在我想获取发布的用户名,而不仅仅是 userId。
所以我使用我的模型 'Users' 和 'Publications' 之间的关联。我已经在我的续集模型和迁移文件中定义了关联,但是当我添加到我的控制器时:
model : User,
attributes: ['firstName']
}],
我收到没有详细信息的错误 400。
如果我只写没有属性的“模型:用户”,它也不起作用,所以我猜它找不到模型用户。
我按照 Sequelize 手册中解释的步骤进行操作,尝试与其他 github 示例进行比较,理论上似乎没问题。我花了两天时间尝试更改字符大小写,我尝试了 sequelize here 提供的许多选项,我删除了所有表格并重新创建了它们,但我现在 运行 在圈子里:-)
在我的迁移文件和模型下面。 感谢您的帮助!
出版物控制器
const models = require('../models'); // importation des modèles sequelize
const Publication = models.publication;
const User = models.user;
exports.getAllPublications = (req, res, next) => {
Publication.findAll({
include: [{
model : User,
attributes: ['firstName']
}],
order: [['createdAt', 'DESC']]
})
.then(
(publications) => {
res.status(200).json(publications);
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};
用户续集模型
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
static associate(models) {
models.User.hasMany(models.Publication)
}
};
User.init({
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN
}, {
sequelize,
modelName: 'User',
});
return User;
};
出版物续集模型
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Publication extends Model {
static associate(models) {
models.Publication.belongsTo(models.User, {
foreignKey: {
allowNull: false,
}
});
}
};
Publication.init({
userId: DataTypes.INTEGER,
title: DataTypes.STRING,
content: DataTypes.STRING
}, {
sequelize,
modelName: 'Publication',
});
return Publication;
};
索引
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
require('dotenv').config() // importation dotenv pour sécuriser passwords
const db = {};
let sequelize;
sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASSWORD, {
host: process.env.DB_HOST,
dialect: process.env.DB_DIALECT
});
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;
db.user = require("./user.js")(sequelize, Sequelize)
db.publication = require("./publication.js")(sequelize, Sequelize)
db.comment = require("./comment.js")(sequelize, Sequelize)
module.exports = db
发布迁移文件
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Publications', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
}
},
title: {
allowNull: false,
type: Sequelize.STRING,
len: [2,50]
},
content: {
allowNull: false,
type: Sequelize.STRING(1234),
len: [2,1000]
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Publications');
}
};
用户创建控制器
exports.signup = (req, res, next) => {
bcrypt.hash(req.body.password, 10) // On crypte le mot de passe (algorithme exécuté 10 fois) / asynchrone
.then(hash => {
console.log(hash)
const newUser = User.create({ // modèle sequelize
lastName : req.body.lastName,
firstName : req.body.firstName,
email: req.body.email,
password: hash, // On enregistre le mdp crypté plutôt que le mdp simple
})
.then((newUser )=> res.status(201).json({ message: 'created' })) // Requête traitée avec succès et création d’un document
.catch(error =>
res.status(400).json({ error })); // Bad Request*/
})
.catch(error => {
console.log("erreur 500")
res.status(500).json({ error })}); // Erreur interne du serveur
};
根据建议更改模型后的新App.js
'use strict'
const express = require('express'); // importation application Express
require('dotenv').config() // importation dotenv pour sécuriser passwords
const mysqlTable = process.env.MYSQLTABLE;
const mysqlUsername = process.env.MYSQLUSERNAME;
const mysqlPassword = process.env.MYSQLPASSWORD;
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
const bodyParser = require('body-parser'); // importation fonction body parser pour extraction objet json de la demande
const cors = require('cors'); // module CORS
const { Sequelize } = require('sequelize'); // importation application Sequelize pour communiquer avec MySQL
const userRoutes = require('./routes/user'); // Importation routeur users
const publicationRoutes = require('./routes/publication'); // Importation routeur posts
const commentRoutes = require('./routes/comment'); // Importation routeur posts
const Publication = require('./models/publication');
const User = require('./models/user')
Publication.belongsTo(User, { Constraints: true, onDelete: 'CASCADE'});
User.hasMany(Publication);
const sequelize = new Sequelize(mysqlTable, mysqlUsername, mysqlPassword, { // Connexion à la base de données mySQL
host : 'localhost',
dialect: 'mysql'
})
const app = express(); // application Express
app.use(bodyParser.json()); // Enregistrement body parser
app.use(cors()); // module CORS
app.use(limiter); // rate limit
app.use((req, res, next) => { // Ajout headers pour résoudre les erreurs CORS
res.setHeader('Access-Control-Allow-Origin', '*'); // accéder à notre API depuis n'importe quelle origine
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization'); // ajouter les headers mentionnés aux requêtes envoyées vers notre API
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS'); // envoyer des requêtes avec les méthodes mentionnées
next();
});
app.use('/api/auth', userRoutes) // Enregistrement routeur users
app.use('/api/publication', publicationRoutes) // Enregistrement routeur publications
app.use('/api/comment', commentRoutes) // Enregistrement routeur publications
module.exports = app;
根据我们交流的意见了解到,问题出在协会的声明上。
我个人不喜欢像你所做的那样定义关联(我没有说它不正确!),我个人喜欢跟随。
我在特定文件下创建了一个Sequelize实例(例如在./util/database.js下):
database.js:
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database_name', 'user_name', 'password', {
dialect: 'mysql',
storage: "./session.mysql",
host: 'localhost'
});
module.exports = sequelize;
我这样定义我的模型:
用户模型:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const User = sequelize.define('user', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
firstName: Sequelize.STRING,
lastName: Sequelize.STRING,
email: Sequelize.STRING,
password: Sequelize.STRING,
isAdmin: Sequelize.BOOLEAN
});
module.exports = User;
出版模式:
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const Publication = sequelize.define('publication', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
title: Sequelize.STRING,
content: Sequelize.STRING
});
module.exports = Publication;
然后,我在 app.js 文件中定义关联:
Publication.belongsTo(User, { Constraints: true, onDelete: 'CASCADE'});
User.hasMany(Publication);
为了确保新数据库的模式得到很好的集成,我使用了 sync
方法和 force
属性(只是第一次,那么你应该删除这个属性并只使用同步方法)
// this will run on starting the server
sequelize
.sync({ force: true }) // run it just in the first time after changing the database, this command will re-draw the database
// .sync()
.then(() => app.listen(8080))
.catch(err => console.log(err));
最后,您可以保留您所做的获取数据的操作,也可以这样做:
User.findByPk(userId, {include: ['publications']})
//supposing that you have an instance of a User (user)
user.getPublications({})
user.getPublications({where: { id: publicationId }})