【问题标题】:How to get attributes from through table in query?如何从查询中的表中获取属性?
【发布时间】:2018-03-10 11:48:03
【问题描述】:

我正在制作一个简单的购物车。我有一个购物车模型、一个产品模型和一个直通表 CartItems。这些是关联:

models.Cart.belongsToMany(models.Product, { through: 'CartItems', as: 'items' })
models.Product.belongsToMany(models.Cart, { through: "CartItems" });

这些是模型的定义:

购物车模型

var Cart = sequelize.define('Cart', {
    userId: {
      allowNull: false,
      type: Sequelize.INTEGER,
      references: {
        model: 'User',
        key: 'id',
      },
    },
    totalPrice: DataTypes.FLOAT
});

产品型号

var Product = sequelize.define('Product', {
    code: DataTypes.STRING,
    name: DataTypes.STRING,
    price: DataTypes.FLOAT
});

CartItems 模型 在这个模型中,我添加了数量和价格属性,因为我在某处读到,最好了解他们下订单时的价格历史记录。还有数量属性,因为我只想在添加另一个产品而不是添加另一行时更改数量。

var CartItem = sequelize.define('CartItem', {
    CartId: DataTypes.INTEGER,
    ProductId: DataTypes.INTEGER,
    quantity: DataTypes.INTEGER,
    price: DataTypes.FLOAT
});

我知道这可能不是做事的最佳方式,但即使我更改了实现,我也想知道:如何访问 through 表中的属性?

具体来说,我正在尝试为结帐功能执行以下操作:

Cart.prototype.checkout = async function () {
    let cartItemArray = await this.getItems({
      include: [{
        model: Product,
        through: {
          attributes: ['quantity'],
        }
      }]
    });
    cartItemArray = cartItemArray.map((item) => {
      return {
        code: item.code,
        price: item.price,
        quantity: item.quantity
      };
    });
    let total = getTotalPrice(cartItemArray);
    return total;
};

【问题讨论】:

  • 最好有价格历史记录,但您不需要根据数量更新价格。你应该把它乘以数量来得到它。如果有任何折扣把它也放在那张桌子上。以便您稍后展示。

标签: javascript node.js sequelize.js


【解决方案1】:

首先,一些警告

警告 1. 您的 Product 模型和 CartItem 模型中都有一个 price 字段。你确定要这个吗?在您尝试编写checkout() 方法时,当您执行item.price 时,您想要获得哪些价格?我的直觉告诉我,您并不是真的想要拥有两个字段,但如果您真的想要,请考虑重命名其中一个以避免歧义。

警告 2。 您的 Cart 模型中有一个 totalPrice... 该字段是否应该跟踪相关产品的价格总和?如果是,那是个坏主意,请完全删除该字段,并在需要总和时立即计算它,因为保持这样的重复数据很容易出错(您必须确保它们同步)。


错误 1

您使用以下代码明确定义了联结表模型,即CartItem

var CartItem = sequelize.define('CartItem', { /* ... */ });

到目前为止一切顺利。但是当你定义多对多关系时,你就犯了一个错误。你使用了through: "CartItems",但你应该使用through: "CartItem"。实际上,这种情况下的最佳实践是直接引用模型,因为您拥有它:through: CartItem。因此,Sequelize 最终会忽略您的模型并自动创建联结表,而无需额外的字段 pricequantity


错误 2

在您尝试编写 checkout() 方法时:

this.getItems({
    include: [{
        model: Product,
        through: {
            attributes: ['quantity'],
        }
    }]
});

这没有意义。回想一下Item 只是您为Product 设置的别名。运行此代码产生SequelizeEagerLoadingError: Product is not associated to Product!

相反,您可以简单地执行 this.getItems() 而不需要任何参数。


错误 3

接下来,您编写代码:

return {
    code: item.code,
    price: item.price,
    quantity: item.quantity
};

这表明您期望quantitycode 一起作为另一个字段出现。这是不正确的。 code 是来自 Product 模型的字段,而 quantity 是来自 CartItem 模型的字段。 Sequelize 不会像这样检索它们“扁平化”。相反,关联本身的字段嵌套在查询结果中,如下所示:

{
    "id": 1,
    "code": null,
    "name": "test",
    "price": null,
    "createdAt": "2018-03-11T19:11:12.862Z",
    "updatedAt": "2018-03-11T19:11:12.862Z",
    "CartItem": {
        "CartId": 1,
        "ProductId": 1,
        "quantity": 2,
        "price": 1.5,
        "createdAt": "2018-03-11T19:11:13.047Z",
        "updatedAt": "2018-03-11T19:11:13.047Z"
    }
}

因此,您应该使用item.CartItem.quantity,而不是那里的item.quantity


总结

标题中问题的答案“如何从查询中的表中获取属性?”只是“只需进行查询,即在您的情况下为this.getItems(),因为属性默认情况下 from through table 进入结果"。

只是你犯了一些其他错误,当然,它没有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    • 2021-04-10
    • 2022-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    相关资源
    最近更新 更多