sequelize关联查询时的分页问题,join,limit

本文介绍Sequelize ORM工具的基本特性和高级查询技巧,包括如何正确使用一对多关联查询,解决分页时条件限制问题,并通过示例说明如何避免常见错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用到许多数据库关系化映射中间件,hibernate,jpa,iBATIS,最近研究nodejs,发现一款不可多得的orm开源工具sequelize,支持promise,映射配置/查询/数据输出等都是json格式,非常顺心,官方文档很标准但完全说不透其强大的功能,很多都需要实际用到才能体会,就像json一样变化多端,你猜不透它有多少种变化。

好,下面来看一个需求案例:
一条这样的普通查询语句:

select * from product join producton product.id=place.productid and place.city=1100 where product.price>100 limit 10

用sequelize的query来写,如果写成这样:

models.product.findAll({
    where: ["price>=?", 100 ],
    include: [{
        model:models.product,
        where: { city:1100 }
    }],
    limit:12
})

实际上运行的sql是这个:

select product.*, place.* from (select * from product where product.price>100 limit 10) join place on product.id=place.productid and place.city=1100

想要的结果是错误的,分页时没有把city:1100 条件限制了,结果有差异,那怎么办?

于是找方法,看到有人使用加subQuery:false条件来处理,如下:

models.product.findAll({
    where: ["price>=?", 100 ],
    include: [{
        model:models.product,
        where: { city:1100 }
    }],
    limit:10,
    subQuery:false   //不让在子查询里分页,全局处理
})

这样对于只含一个include关联的查询倒是问题不大,如果include多个对象,关联的对象有1对多,多对多的关系,就不好控制了。

我的解决方法是,在需要一对一关联的表中加入required:true,这样就会将这个条件放在分页之前执行,

models.product.findAll({
    where: ["price>=?", 100 ],
    include: [{
        model:models.product,
        where: { city:1100 },
        required:true  //inner join方式
    }],
    limit:10,
})

运行时sql如下:

select product.*,place.* from product join place on product.id=place.productid and place.city=1100 where product.price>100 limit 10

required参数一般是指关联对象是外联还是内联,内联required=true可以表示内联条件优先,分页在后。
以上内容进仅供参考,使用场景不同,理解也不一样。

'use strict'; const { Model } = require('sequelize'); module.exports = (sequelize, DataTypes) => { class Product extends Model { /** * Helper method for defining associations. * This method is not a part of Sequelize lifecycle. * The `models/index` file will call this method automatically. */ static associate(models) { models.Product.belongsTo(models.ProductCategory, { foreignKey: 'category_id' }); models.Product.belongsTo(models.Merchant, { foreignKey: 'merchant_id' }); } } Product.init({ product_name: { type: DataTypes.STRING, allowNull: false, validate: { notEmpty: true, len: [1, 255] } }, stock: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, validate: { isInt: true, min: 0 } }, merchant_id: { type: DataTypes.INTEGER, allowNull: false, validate: { isInt: true, min: 1 }, async isPresent(value) { const merchant = await sequelize.models.Merchant.findByPk(value); if (!merchant) { throw new Error(`ID为${value}的商家不存在`); } } }, category_id: { type: DataTypes.INTEGER, allowNull: false, validate: { isInt: true, min: 1 }, async isPresent(value) { const category = await sequelize.models.ProductCategory.findByPk(value); if (!category) { throw new Error(`ID为${value}的分类不存在`); } } }, price: { type: DataTypes.DECIMAL(10, 2), allowNull: false, validate: { isDecimal: true, min: 0.01 } }, sales: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, validate: { isInt: true, min: 0 } }, specifications: { type: DataTypes.STRING, allowNull: true, validate: { len: [0, 500] } }, image: { type: DataTypes.STRING, allowNull: true, validate: { isUrl: true // 确保图片字段是有效的 URL } }, description: { type: DataTypes.TEXT, allowNull: true, validate: { len: [0, 5000] } } }, { sequelize, modelName: 'Product', }); return Product; }; 请根据这个sequelize模型写一个今日推荐商品的功能, exports.xxx = asycn(req,res)=>{功能内容},注意,该项目是nodejs
03-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值