我将 objection.js 和 knex.js 用于我的 RESTful API。
在我的数据库中,我有三个表: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',
},
],
},
];
答案 0 :(得分:0)
我认为您尝试编写的 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'
)
)