prismaで1:Nのソートで苦戦している。
ユーザー一覧ページで、現在の売上が高い順にランキング形式で表示させたいのだが、どうもうまくいかない。
https://github.com/prisma/prisma/issues/5008 と同じ問題に直面している。
仕様
仕様を雑に書く。
売上管理システム
1:NなCustomer:dailyEarning
dailyEarningは前日の売上が保存する
dailyEarning.currentEarningは、Customerがシステムに登録した日を起算日として、当日6時までの売上情報が保存する
dailyEarningは毎日6時に更新される
スキーマ
1
2
3
4
5
6
7
8
9
10
11
12
13
model Customer {
custId Int @ id @ default ( autoincrement ())
name String
dailyEarnings DailyEarning []
}
model dailyEarning {
dailyEarningId Int @ id @ default ( autoincrement ())
dailyEarning Float //昨日1日の売上
currentEarning Float //現在までの売上
owner Customer @ relation ( fields : [ ownerId ], references : [ id ])
ownerId Int
}
Prisma Clientでソート
現在までの売上をランキング形式で表示したい。
dailyEarning.currentEarning
の額でソートして、降順でデータを返却することにする。
「現在まで売上が多い順にして全てのユーザーを返却」
下記のような感じで描きたいが、OrderByの中にincludeをネストさせる書き方はprismaに存在しない。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const getCustomers = await prisma . customer . findMany ({
orderBy :
include : {
| dailyEarnings : {
take : 1 ,
orderBy : {
currentEarning : 'desc' ,
},
select : {
currentEarning : true ,
},
}
},
});
$queryRaw
は使いたくない。prismaの恩恵が受けられないから。
const queryCustomersOrderBycurrentEarningsDesc = 'SELECT * FROM Customer c LEFT INNER JOIN dailyEarning de ON(c.customerId = de.ownerId ) ORDER BY de.currentEarning DESC'
一番近いクエリーはこんな感じだけど、なんか違う。dailyEarningsがソートされて返ってくるだけ。
const getCustomer = await prisma . customer . findMany ({
include : {
| dailyEarnings : {
orderBy : {
currentEarning : 'desc' ,
},
select : {
currentEarning : true ,
},
},
});
返却されるjson
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[
{
"customerId" : 5 ,
"name" : "Genuine Person" ,
"dailyEarnings" : [
{
"currentEarning" : 10000000
},
{
"currentEarning" : 2392000
},
{
"currentEarning" : -120000
}
]
},
{
"customerId" : 5 ,
"name" : "Yo Solo" ,
"dailyEarnings" : [
{
"currentEarning" : 50000000000
},
{
"currentEarning" : 1942000
},
{
"currentEarning" : -100000000
}
]
}
]
chatGPTに聞いた
結局GPTさんに聞いたらそれっぽい回答が返ってきた。
本当は一つの文で完結させたかったけど、仕方ない。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. dailyEarningsで最大のcurrentEarningを持つcustomerを見つける
const dailyEarningsMax = await prisma . dailyEarnings . findMany ({
select : {
customerId : true ,
currentEarning : true ,
},
orderBy : {
currentEarning : 'desc' ,
},
take : 1 ,
});
// 2. その結果を使ってcustomerをソートする
const sortedCustomers = await prisma . customer . findMany ({
where : {
id : {
in : dailyEarningsMax . map (( dailyEarning ) => dailyEarning . customerId ),
},
},
orderBy : {
id : 'asc' , // Or any other sorting condition
},
});
まとめ