我在我的RESTful API中使用了objection.js和knex.js。
在我的数据库中,我有三个表:products、characteristics和product_characteristics (具有额外列“value”的连接表)。
所以我要做的是获取所有具有相应特征值的产品。
在GET请求中,我接受一个characteristics查询参数并对其进行解析,以获得用于过滤产品的特征数组。
已解析的特征数组:
[{
characteristicId: number,
value: string
}, ...]‘'products’表字段:
[id, title, price, discount]‘特征表字段:
[id, name]'product_characteristics‘连接表字段:
[productId, characteristicId, value]目前,我使用objection的queryBuilder和withGraphFetch方法以及page和limit方法获取所有产品:
const query: any = ProductModel.query()
.page(page - 1, limit)
.orderBy(sortBy, order)
.withGraphFetched({
category: true,
images: true,
characteristics: true,
});
const result = await query;
return {
products: result.results,
total: result.total,
};Objection.js提供了withGraphJoined方法,该方法允许访问queryBuilder中的相关实体,以便可以用于根据关系过滤parentModel,但它不支持page和limit方法。
因此,一种可能的解决方案是使用knex.raw()方法执行原始SQL查询。但是我花了一天的时间尝试编写原始SQL查询来获取所有需要的数据。
理想的结果是一个经过特征过滤的产品数组,所有与产品相关的特征都作为JSON响应参数。
const products = [
{
id: 1,
title: 'Pipe 1',
price: 3000,
discount: 500,
characteristics: [
{
id: 1,
name: 'diameter',
value: '120 mm',
},
{
id: 2,
name: 'color',
value: 'black',
},
],
},
{
id: 2,
title: 'Pipe 2',
price: 5000,
discount: 0,
characteristics: [
{
id: 1,
name: 'diameter',
value: '120 mm',
},
{
id: 2,
name: 'color',
value: 'blue',
},
],
},
];发布于 2021-07-21 19:51:05
我认为您尝试编写的SQL查询是
SELECT
p.id,
p.title,
p.price,
p.discount,
c.name characteristicName,
pc.value characteristicValue
FROM
products p
INNER JOIN product_characteristics pc ON pc.productId = p.id
INNER JOIN characteristics c ON c.id = pc.characteristicId
WHERE
(c.id = 1 AND pc.value = 'value1')
OR (c.id = 2 AND pc.value = 'value2')
OR (c.id = 3 AND pc.value = 'value3')在knex中可以实现如下所示:
knex({p: 'products'})
.join({pc: 'product_characteristics'}, 'pc.productId', '=', 'p.id')
.join({c: 'characteristics'}, 'c.id', '=', 'pc.characteristicId')
.where(builder =>
characteristics.forEach(item =>
builder.orWhere(builder =>
builder
.andWhere('c.id', '=', item.characteristicId)
.andWhere('pc.value', '=', item.value)
)
)
)
.select('p.id', 'p.title', 'p.price' /* etc */)您可以很容易地向其中添加.offset()和.limit(),以支持分页。它将转换为以下SQL:
select
"p"."id",
"p"."title",
"p"."price"
from
"products" as "p"
inner join "product_characteristics" as "pc" on "pc"."productId" = "p"."id"
inner join "characteristics" as "c" on "c"."id" = "pc"."characteristicId"
where
(
(
"c"."id" = 1
and "pc"."value" = 'value1'
)
or (
"c"."id" = 2
and "pc"."value" = 'value2'
)
or (
"c"."id" = 3
and "pc"."value" = 'value3'
)
)https://stackoverflow.com/questions/68464438
复制相似问题