Node.js 尝试将行插入表时出错,因为UUID外键为sequelize.js

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中尝试了一个手动脚本,它成功了。 我可能在代码方面遗漏了一些东西,但我不知道是什么 这是邮递员返回给我的错误- {

我将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项代码,并用我的真实模型替换了它,因此我不能确定,但现在一切都很好。我很确定这个问题确实与路由器路径中的错误命名有关。