JavaScriptを有効にしてください

【Prisma】1:Nのランキング作成に苦戦

 ·  ☕ 2 分で読めます  ·  🐙 subaru

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の恩恵が受けられないから。

1
const queryCustomersOrderBycurrentEarningsDesc = 'SELECT * FROM Customer c LEFT INNER JOIN dailyEarning de ON(c.customerId = de.ownerId ) ORDER BY de.currentEarning DESC'

一番近いクエリーはこんな感じだけど、なんか違う。dailyEarningsがソートされて返ってくるだけ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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
  },
});

まとめ

  • 仕様を固めてGPTに渡せば、問題は解決する。

octpsubaru
著者
subaru
Web Developer