Node.js 尝试将行插入表时出错,因为UUID外键为sequelize.js
我将sequelize.js与node.js和postgres一起使用。 我从一个例子中得到了两个简单的表作为“POC”。 我将ID更改为UUID,并且在插入第二个表(UUID FK)时遇到问题 我正在用邮递员来测试它。 我正在使用UUID创建todo行,没有问题, 然后,我尝试创建一个todo项,该项将todo id作为外键 而且它似乎无法识别该ID 我在postgres中尝试了一个手动脚本,它成功了。 我可能在代码方面遗漏了一些东西,但我不知道是什么 这是邮递员返回给我的错误-Node.js 尝试将行插入表时出错,因为UUID外键为sequelize.js,node.js,postgresql,orm,sequelize.js,Node.js,Postgresql,Orm,Sequelize.js,我将sequelize.js与node.js和postgres一起使用。 我从一个例子中得到了两个简单的表作为“POC”。 我将ID更改为UUID,并且在插入第二个表(UUID FK)时遇到问题 我正在用邮递员来测试它。 我正在使用UUID创建todo行,没有问题, 然后,我尝试创建一个todo项,该项将todo id作为外键 而且它似乎无法识别该ID 我在postgres中尝试了一个手动脚本,它成功了。 我可能在代码方面遗漏了一些东西,但我不知道是什么 这是邮递员返回给我的错误- {
{
"name": "SequelizeDatabaseError",
"parent": {
"name": "error",
"length": 96,
"severity": "ERROR",
"code": "22P02",
"file": "uuid.c",
"line": "137",
"routine": "string_to_uuid",
"sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
},
"original": {
"name": "error",
"length": 96,
"severity": "ERROR",
"code": "22P02",
"file": "uuid.c",
"line": "137",
"routine": "string_to_uuid",
"sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
},
"sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
}
以下是相关的js文件-
todoItems.js控制器-
const TodoItem = require('../dal/models').TodoItem;
const uuid = require('uuid/v4');
module.exports = {
create(req, res) {
return TodoItem
.create({
content: req.body.content,
todoId: req.params.todoId,
})
.then(todoItem => res.status(201).send(todoItem))
.catch(error => res.status(400).send(error));
},
update(req, res) {
return TodoItem
.find({
where: {
id: req.params.todoItemId,
todoId: req.params.todoId,
},
})
.then(todoItem => {
if (!todoItem) {
return res.status(404).send({
message: 'TodoItem Not Found',
});
}
return todoItem
.update({
content: req.body.content || todoItem.content,
complete: req.body.complete || todoItem.complete,
})
.then(updatedTodoItem => res.status(200).send(updatedTodoItem))
.catch(error => res.status(400).send(error));
})
.catch(error => res.status(400).send(error));
},
destroy(req, res) {
return TodoItem
.find({
where: {
id: req.params.todoItemId,
todoId: req.params.todoId,
},
})
.then(todoItem => {
if (!todoItem) {
return res.status(404).send({
message: 'TodoItem Not Found',
});
}
return todoItem
.destroy()
.then(() => res.status(204).send())
.catch(error => res.status(400).send(error));
})
.catch(error => res.status(400).send(error));
},
};
todos.js控制器-
const Todo = require('../dal/models').Todo;
const TodoItem = require('../dal/models').TodoItem;
module.exports = {
create(req, res) {
return Todo
.create({
title: req.body.title,
})
.then((todo) => res.status(201).send(todo))
.catch((error) => res.status(400).send(error));
},
list(req, res) {
return Todo
.findAll({
include: [{
model: TodoItem,
as: 'todoItems',
}],
order: [
['createdAt', 'DESC'],
[{ model: TodoItem, as: 'todoItems' }, 'createdAt', 'ASC'],
],
})
.then((todos) => res.status(200).send(todos))
.catch((error) => res.status(400).send(error));
},
retrieve(req, res) {
return Todo
.findByPk(req.params.todoId, {
include: [{
model: TodoItem,
as: 'todoItems',
}],
})
.then((todo) => {
if (!todo) {
return res.status(404).send({
message: 'Todo Not Found',
});
}
return res.status(200).send(todo);
})
.catch((error) => res.status(400).send(error));
},
update(req, res) {
return Todo
.findByPk(req.params.todoId, {
include: [{
model: TodoItem,
as: 'todoItems',
}],
})
.then(todo => {
if (!todo) {
return res.status(404).send({
message: 'Todo Not Found',
});
}
return todo
.update({
title: req.body.title || todo.title,
})
.then(() => res.status(200).send(todo))
.catch((error) => res.status(400).send(error));
})
.catch((error) => res.status(400).send(error));
},
destroy(req, res) {
return Todo
.findByPk(req.params.todoId)
.then(todo => {
if (!todo) {
return res.status(400).send({
message: 'Todo Not Found',
});
}
return todo
.destroy()
.then(() => res.status(204).send())
.catch((error) => res.status(400).send(error));
})
.catch((error) => res.status(400).send(error));
},
};
todo表创建迁移-
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.createTable('Todos', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
title: {
type: Sequelize.STRING,
allowNull: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
}),
down: (queryInterface /* , Sequelize */) => queryInterface.dropTable('Todos'),
};
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.createTable('TodoItems', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
content: {
type: Sequelize.STRING,
allowNull: false,
},
complete: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
todoId: {
type: Sequelize.UUID,
onDelete: 'CASCADE',
references: {
model: 'Todos',
key: 'id',
as: 'todoId',
},
},
}),
down: (queryInterface /* , Sequelize */) =>
queryInterface.dropTable('TodoItems'),
};
todo项表创建迁移-
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.createTable('Todos', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
title: {
type: Sequelize.STRING,
allowNull: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
}),
down: (queryInterface /* , Sequelize */) => queryInterface.dropTable('Todos'),
};
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.createTable('TodoItems', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
content: {
type: Sequelize.STRING,
allowNull: false,
},
complete: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
todoId: {
type: Sequelize.UUID,
onDelete: 'CASCADE',
references: {
model: 'Todos',
key: 'id',
as: 'todoId',
},
},
}),
down: (queryInterface /* , Sequelize */) =>
queryInterface.dropTable('TodoItems'),
};
todo模型-
const uuid = require('uuid/v4');
'use strict';
module.exports = (sequelize, DataTypes) => {
const Todo = sequelize.define('Todo', {
title: {
type: DataTypes.STRING,
allowNull: false,
}
});
Todo.associate = (models) => {
Todo.hasMany(models.TodoItem, {
foreignKey: 'todoId',
as: 'todoItems',
});
};
Todo.beforeCreate((item, _ ) => {
return item.id = uuid();
});
return Todo;
};
待办事项模型-
const uuid = require('uuid/v4');
'use strict';
module.exports = (sequelize, DataTypes) => {
const TodoItem = sequelize.define('TodoItem', {
content: {
type: DataTypes.STRING,
allowNull: false,
},
complete: {
type: DataTypes.BOOLEAN,
defaultValue: false,
}
});
TodoItem.associate = (models) => {
TodoItem.belongsTo(models.Todo, {
foreignKey: 'todoId',
onDelete: 'CASCADE',
});
};
TodoItem.beforeCreate((item, _ ) => {
return item.id = uuid();
});
return TodoItem;
};
你的路由器代码是什么样子的?您是否为todoId使用了正确的路径参数?例如,如果您使用的是express。它应该看起来像
app.post(“/todos/:todoId/todo\u items”,todoItemController.create)
。请注意camelcase todoId。这将确保您在todoItems控制器中引用的req.params.todoId
具有正确的值
另外,确保您有一个正确的主体解析器来正确处理req.body.content。在express中,这将通过body-body-parser库和
app.use(bodyParser.json())
完成。在todoItem控制器创建代码中添加断点或日志语句,并验证您实际具有正确的参数值 如果出现上述错误,可能是因为您在请求主体中嵌套了其他实体,因此UUID没有从字符串转换为UUID
例如,如果您有一个请求主体,如
{
"Transaction": {
"id" : "f2ec9ecf-31e5-458d-847e-5fcca0a90c3e",
"currency" : "USD",
"type_id" : "bfa944ea-4ce1-4dad-a74e-aaa449212ebf",
"total": 8000.00,
"fees": 43.23,
"description":"Description here"
},
}
因此,在控制器中,您正在创建实体,如
try {
await Transaction.create(
{
id: req.body.Transaction.id,
currency: req.body.Transaction.currency,
type_id: req.body.Transaction.type_id,
total: req.body.Transaction.total,
fees: req.body.Transaction.fees,
description: req.body.Transaction.description,
}......
您的id
和type\u id
很可能没有从字符串转换为UUID
解决这个问题有多种方法。最直接的方法是执行从字符串到UUID的显式转换
为此,请从uuid npm模块导入parse
,并进行显式转换,如下面的代码示例所示
const { parse: uuidParse } = require("uuid");
try {
await Transaction.create(
{
id: uuidParse(req.body.Transaction.id),
currency: req.body.Transaction.currency,
type_id: uuidParse(req.body.Transaction.type_id),
total: req.body.Transaction.total,
fees: req.body.Transaction.fees,
description: req.body.Transaction.description,
}.....
这种从字符串到UUID的显式转换将主要解决这个问题。遗憾的是,我删除了todo项代码,并用我的真实模型替换了它,因此我不能确定,但现在一切都很好。我很确定这个问题确实与路由器路径中的错误命名有关。