nodejs sequelize 多表分页查询,返回结果包含两表字段

寻技术 JS脚本 / Node.Js 2023年07月09日 195

goods和goodsSkus表

实现 两表联表查询,并分页。查询结果中包含两表中的字段,重点在于子表中返回字段 要写在include中的attributes中,否则生成的sql无法执行

let queryParams={
  name: {
    [sequelize.Op.like]: `%$测试%`
  }
}

let skuQueryParams = {
  name: {
    [sequelize.Op.like]: `%$x%`
  }
}

 

daGoodsModel.hasMany(daGoodsSkuModel, {foreignKey: 'goods_id'});
 
var results = await daGoodsModel.findAll({
    order:      [['id','asc']],
    where:      queryParams,
    raw:        true,
    include:  [
        {
            model: daGoodsSkuModel, 
            attributes:[ 
                [sequelize.col('id'), 'sku_id'],
                [sequelize.col('name'), 'sku_name']
            ],
            where: skuQueryParams,
            require: true
        }
    ],
    attributes:  [
        'id','name'
    ],
    limit:  pageSize,
    offset: (pageIndex - 1) * pageSize
});

sku表返回字段放到include.attributes中生成的sql

SELECT `da_goods`.*, `da_goods_skus`.`id` AS `da_goods_skus.sku_id`, `da_goods_skus`.`name` AS `da_goods_skus.sku_name`
FROM (
	SELECT `da_goods`.`id`, `da_goods`.`name`
	FROM `da_goods` `da_goods`
	WHERE ((`da_goods`.`name` LIKE '%测试%'
			OR `da_goods`.`subtitle` LIKE '%测试%')
		AND `da_goods`.`deleted` = false
		AND (
			SELECT `goods_id`
			FROM `da_goods_sku` `da_goods_skus`
			WHERE `da_goods_skus`.`deleted` = false
				AND `da_goods_skus`.`name` LIKE '%x%'
				AND `da_goods_skus`.`goods_id` = `da_goods`.`id`
			LIMIT 1
		) IS NOT NULL)
	ORDER BY `da_goods`.`id` ASC
	LIMIT 0, 10
) `da_goods`
	INNER JOIN `da_goods_sku` `da_goods_skus`
	ON (`da_goods`.`id` = `da_goods_skus`.`goods_id`
		AND `da_goods_skus`.`deleted` = false
		AND `da_goods_skus`.`name` LIKE '%x%')
ORDER BY `da_goods`.`id` ASC;

 

sku返回字段放到attributes中

var results = await daGoodsModel.findAll({
	order:      [['id','asc']],
	where:      queryParams,
	raw:        true,
	include:  [
		{
		    model: daGoodsSkuModel, 
		    attributes:[],
		    where: skuQueryParams,
		    require: true
		}
	],
	attributes:  [
            'id','name',
            [sequelize.col('da_goods_skus.id'), 'sku_id'],
            [sequelize.col('da_goods_skus.name'), 'sku_name']
	],
	limit:  pageSize,
	offset: (pageIndex - 1) * pageSize
});

 生成的sql语句,如下语句执行失败,会报 "Unknown column 'da_goods_skus.id' in 'field list'",因为标红部分查询不到

SELECT `da_goods`.*
FROM (
    SELECT `da_goods`.`id`, `da_goods`.`name`, `da_goods_skus`.`id` AS `sku_id`, `da_goods_skus`.`name` AS `sku_name`
    FROM `da_goods` `da_goods`
    WHERE ((`da_goods`.`name` LIKE '%测试%'
            OR `da_goods`.`subtitle` LIKE '%测试%')
        AND `da_goods`.`deleted` = false
        AND (
            SELECT `goods_id`
            FROM `da_goods_sku` `da_goods_skus`
            WHERE `da_goods_skus`.`deleted` = false
                AND `da_goods_skus`.`name` LIKE '%x%'
                AND `da_goods_skus`.`goods_id` = `da_goods`.`id`
            LIMIT 
        ) IS NOT NULL)
    ORDER BY `da_goods`.`id` ASC
    LIMIT , 10
) `da_goods`
    INNER JOIN `da_goods_sku` `da_goods_skus`
    ON (`da_goods`.`id` = `da_goods_skus`.`goods_id`
        AND `da_goods_skus`.`deleted` = false
        AND `da_goods_skus`.`name` LIKE '%x%')
ORDER BY `da_goods`.`id` ASC;

 

 

正确返回结果 ,需要对返回字段进行处理,去掉 da_goods_skus

[
	{
		"id": 334,
		"name": "测试商品",
		"da_goods_skus.sku_id": 506,
		"da_goods_skus.sku_name": "xl"
	},
	{
		"id": 334,
		"name": "测试商品",
		"da_goods_skus.sku_id": 507,
		"da_goods_skus.sku_name": "x"
	}
]

 

但是上面node生成sql两层嵌套,总感觉有问题,并且分页查询时如果与goods对应的sku表有多条数据,会返回所有sku,经查是sequelize对sql进行了优化,添加 subQuery:false,即可

代码

var results = await daGoodsModel.findAll({
    order:      [['id','asc']],
    subQuery:   false,
    where:      queryParams,
    include:  [
        {
            model: daGoodsSkuModel, 
            attributes:[],
            where: skuQueryParams
        }
    ],
    attributes:  [
        'id','name',
        [sequelize.col('da_goods_skus.id'), 'sku_id'],
        [sequelize.col('da_goods_skus.name'), 'sku_name'],
    ],
    limit:  pageSize,
    offset: (pageIndex - 1) * pageSize
});

 

生成SQL

SELECT `da_goods`.`id`, `da_goods`.`name`, `da_goods_skus`.`id` AS `sku_id`, `da_goods_skus`.`name` AS `sku_name`
FROM `da_goods` `da_goods`
    INNER JOIN `da_goods_sku` `da_goods_skus`
    ON `da_goods`.`id` = `da_goods_skus`.`goods_id`
        AND `da_goods_skus`.`deleted` = false
WHERE `da_goods`.`deleted` = false
ORDER BY `da_goods`.`id` ASC
LIMIT , ;

 

 但是这样返回的sku永远只有一条,也就是goods有几条,返回几条记录,对应的sku只返回一条

[{
    "id": 334,
    "name": "测试商品",
    "sku_id": 506,
    "sku_name": "xl",
},
{
    "id": 335,
    "name": "测试1",
    "sku_id": 508,
    "sku_name": "aaa",
}]

还是有问题

将sku返回字段放到include.attributes 解决问题

var results = await daGoodsModel.findAndCountAll({
    order:      [['id','asc'],[sequelize.col('da_goods_skus.id'),'asc']],
    subQuery:   false,
    where:      queryParams,
    include:  [
        {
            model: daGoodsSkuModel, 
            attributes:[                        
                [sequelize.col('id'), 'sku_id'],
                [sequelize.col('name'), 'sku_name']
            ],
            where: skuQueryParams
        }
    ],
    attributes:  [
        'id','name'
    ],
    limit:  pageSize,
    offset: (pageIndex - 1) * pageSize
});

 

返回结果

[{
    "id": 334,
    "name": "测试商品",
    "da_goods_skus": [
        {
            "sku_id": 506,
            "sku_name": "xl"
        },
        {
            "sku_id": 507,
            "sku_name": "x"
        }
    ],
},
{
    "id": 335,
    "name": "测试1",
    "da_goods_skus": [
        {
            "sku_id": 508,
            "sku_name": "aaa"
        }
    ]
}]

 

https://blog.zeromake.com/pages/sequelize-trap/

关闭

用微信“扫一扫”