【问题标题】:Node JS API Sequelize PostgreSQL UUID as primary key return error "column Nan does not exist"Node JS API Sequelize PostgreSQL UUID 作为主键返回错误“Nan 列不存在”
【发布时间】:2021-04-04 08:17:45
【问题描述】:

我正在为一个使用 Node JSPostgreSQLSequelize 的简单电子商务应用程序的后端开发 REST API,当我尝试将产品添加到购物车时,我遇到了 Sequelize 的问题。它返回错误"column Nan does not exist"
最初我使用整数作为用户 ID 作为主键,然后我更改为 UUID 以更好地适应目的。

我用于模型和迁移的代码如下:

//User model
export default (sequelize, DataTypes) => {
  const User = sequelize.define(
    'User',
    {
      id: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
        allowNull: false,
        primaryKey: true,
        unique: true,
      },
      name: {
        type: DataTypes.STRING,
        allowNull: false
      },
      password: {
        type: DataTypes.STRING,
        allowNull: false
      },
      email: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: {
          name: 'user_email',
          msg: 'A user with this email already exists.'
        }
      },
    },
  User.associate = models => {
    User.hasOne(models.Cart, {
      foreignKey: 'userId',
      as: 'cart',
      onDelete: 'cascade'
    });
  };

  User.associate = models => {
    User.hasMany(models.Order, {
      foreignKey: 'userId',
      as: 'orders',
      onDelete: 'cascade'
    });
  };

  return User;
};

//User migration
export const up = (queryInterface, Sequelize) =>
  queryInterface.createTable('Users', {
    id: {
      type: Sequelize.UUID,
      defaultValue: Sequelize.UUIDV4,
      allowNull: false,
      primaryKey: true,
      unique: true,
    },
    name: {
      allowNull: false,
      type: Sequelize.STRING
    },
    password: Sequelize.STRING,
    email: {
      allowNull: false,
      type: Sequelize.STRING,
      unique: true
    },
    createdAt: {
      allowNull: false,
      type: Sequelize.DATE,
      defaultValue: Sequelize.fn('now')
    },
    updatedAt: {
      allowNull: false,
      type: Sequelize.DATE,
      defaultValue: Sequelize.fn('now')
    },
  });

export const down = queryInterface => queryInterface.dropTable('Users');

购物车模型

export default (sequelize, DataTypes) => {
  const Cart = sequelize.define('Cart', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      allowNull: false,
      primaryKey: true,
    },
    userId: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      allowNull: false
    },
    cartItem: {
      type: DataTypes.TEXT,
      allowNull: false,
      get(value) {
        return JSON.parse(this.getDataValue(value));
      },
      set(value) {
        this.setDataValue('cartItem', JSON.stringify(value));
      }
    }
  });

  Cart.associate = models => {
    Cart.belongsTo(models.User, {
      foreignKey: 'userId',
      as: 'owner'
    });
  };
  return Cart;
};

购物车迁移

export const up = (queryInterface, Sequelize) =>
  queryInterface.createTable('Carts', {
    id: {
      allowNull: false,
      primaryKey: true,
      type: Sequelize.UUID,
      defaultValue: Sequelize.UUIDV4,
    },
    userId: {
      type: Sequelize.UUID,
      defaultValue: Sequelize.UUIDV4,
      allowNull: false
    },
    cartItem: {
      type: Sequelize.TEXT,
      allowNull: false
    },
    createdAt: {
      allowNull: false,
      type: Sequelize.DATE,
      defaultValue: Sequelize.fn('now')
    },
    updatedAt: {
      allowNull: false,
      type: Sequelize.DATE,
      defaultValue: Sequelize.fn('now')
    }
  });

export const down = queryInterface => queryInterface.dropTable('Carts');

处理添加到购物车的代码:

addToCart() {
    return this.asyncWrapper(async (req, res) => {
      const { body, user } = req;

      body.userId = user.id;
      const cart = await this.service.addToCart(body);

      this.sendResponse(res, cart, undefined, 201);
    });
  }

加入购物车服务

async cart(userId, options = {}) {
    const cart = await super.find({ userId }, options);
    return cart;
  }

  async addToCart(data, options) {
    const { userId, productId, qty } = data;

    const [result] = await this.model.findOrCreate({
      where: { userId: +userId },
      defaults: { cartItem: new CartItem() }
    });

    const cartData = JSON.parse(result.dataValues.cartItem);
    const cartItem = new CartItem(cartData);

    const product = await ProductService.getById(productId, { plain: true });

    ExceptionHandler.throwErrorIfNull(product);

    const cart = cartItem.addToCart(product, qty);

    result.cartItem = cart;
    result.save();

    return result;
  }

Sequelize 生成的 SQL 查询如下:
SELECT "id","userId","cartItem","createdAt","updatedAt" FROM "Carts" AS "Cart" WHERE "Cart"."userId" = NaN LIMIT 1;

目标是使用 UUID 作为数据库中的主键。 当我将数据类型从 Integer 更改为 UUID 时,这个问题就开始了,我看不出代码有什么问题。

关于如何解决这个问题的任何建议?

Sequelize version: "^5.21.9" with "pg": "^8.2.0" and "pg-hstore": "^2.3.3".

【问题讨论】:

  • 您能分享您的模型代码,以及将 userId 传递到查询中的代码吗?
  • @Noah 型号代码是已经在帖子中的购物车模式。处理查询的代码如下:addToCart() { return this.asyncWrapper(async (req, res) => { const { body, user } = req; body.userId = user.id; const cart = await this.service.addToCart(body); this.sendResponse(res, cart, undefined, 201); }); }
  • 显示this.service.addToCart 代码。请将其添加到您的帖子中,而不是在此处作为评论
  • 另外你不需要在User模型的PK字段中指明uniquedefaultValue选项,因为它已经是一个主键(这意味着唯一)并且它的默认值是由生成的D B。您还需要在模型的 PK 字段中指出 autoIncrement: true,以便 Sequelize 知道 DB 应该生成一个默认值
  • @Anatoly autoIncrement: true 不起作用,因为我使用的是 UUID 标识符

标签: javascript node.js postgresql sequelize.js sequelize-cli


【解决方案1】:

如果您将数据类型从 INTEGER 切换到 UUID,则不应尝试将 UUID 字符串转换为执行 where: { userId: +userId } 的数字。

按原样传递userId

where: { userId }

【讨论】:

  • 成功了!谢谢!这是我的一个愚蠢的错误,我完全忘记了改变这个转换。现在它工作正常。
猜你喜欢
  • 2018-10-29
  • 1970-01-01
  • 2015-08-14
  • 1970-01-01
  • 2021-04-05
  • 2021-05-29
  • 2023-02-21
  • 2021-10-20
  • 2021-06-03
相关资源
最近更新 更多