【Drizzle ORM】JOINした結果をマッピングして集計する
const rows = await this.db .select({ user: usersTable, post: postsTable, }) .from(usersTable) .leftJoin(postsTable, eq(usersTable.id, postsTable.userId));
Drizzle ORMで複数テーブルをJOINしSELECTする時。
[ { user: { id: 1, name: 'user1', }, post: [ { id: 1, title: 'post1', }, { id: 2, title: 'post2', }, ], },];
[ { user: { id: 1, name: 'user1', }, post: { id: 1, title: 'post1', }, }, { user: { id: 1, name: 'user1', }, post: { id: 2, title: 'post2', }, },];
他のORMに慣れているとuser
に紐づくpost
一覧がマッピングされたレコードが返ってくるのを期待してしまうが、Drizzle ORMはクエリ実行結果のまま返す1ので、これをマッピングしたい。
解決法
type User = InferModel<typeof usersTable>;type Post = InferModel<typeof postsTable>;
const rows = await this.db .select({ user: usersTable, post: postsTable, }) .from(usersTable) .leftJoin(postsTable, eq(usersTable.id, postsTable.userId));
const map = rows.reduce<Map<number, { user: User; posts: Post[] }>>( (acc, { user, post }) => { if (!acc.has(user.id)) { acc.set(user.id, { user, posts: [] }); } if (post) acc.get(user.id)?.posts.push(post);
return acc; }, new Map(),);const result = [...map.values()];
Array.reduce()
とMap
を用いて自前でマッピングする2のが最もシンプルそう。
参考
-
Drizzle Queriesを利用した場合を除く ↩