Next.js Discord

Discord Forum

How do i properly cache database queries

Answered
Barbary Lion posted this in #help-forum
Open in Discord
Barbary LionOP
Hey, in this page i get all messages from my database and render them, I feel like im doing something wrong for the cache, can someone help me?
im using drizzle

import type { Metadata } from 'next';
import Client from './component.client';
import getSession from '@/lib/getSession';
import { redirect } from 'next/navigation';
import { db, schema } from '@/db';
import { cache } from 'react';
import { eq } from 'drizzle-orm';
import Image from 'next/image';
import Link from 'next/link';

export const metadata: Metadata = {
 title: 'Only Programmers - Settings',
};

const getCachedGlobalMessage = cache(async () => {
 return await db.query.globalMessage.findMany();
});
const getUserById = cache(async (id: string) => {
 return await db.query.user.findFirst({
  where: eq(schema.user.id, id),
 });
});
const getMessages = async () => {
 const allGlobalMessages = await getCachedGlobalMessage();
 return Promise.all(
  allGlobalMessages.map(async message => {
   const creator = await getUserById(message.createdBy);
   return {
    ...message,
    creator,
   };
  }),
 );
};

export default async function Page() {
 const session = await getSession();
 const user = session?.user;
 if (!user) {
  redirect('/auth?callbackUrl=/settings');
 }
 const messages = await getMessages();
 return (
  <main className='px-3 py-10'>
   <section className='mx-auto max-w-7xl space-y-6'>
    <div className='mx-auto max-w-2xl'>
     <Client />
     <div className='mt-8'>
      <ul className='flex flex-col gap-4'>
       {messages.map(data => (
        <li className='flex min-h-24 flex-row items-center gap-2 rounded border border-[var(--border)] px-2 py-8 shadow-sm'>
         <Link href={`$/profile/${data.creator?.id}`}>
          <Image src={data.creator?.image || ''} className='rounded-full' alt={`${data.creator?.name}'s profile`} width={32} height={32} />
         </Link>
         {data.content}
        </li>
       ))}
      </ul>
     </div>
    </div>
   </section>
  </main>
 );
}
Answered by Arinji
use unstable_cache
View full answer

57 Replies

@Barbary Lion
its wrong
react cache dosent cache, it dedupes
use unstable_cache
Answer
@Arinji <@827457999978102835>
Barbary LionOP
what does dedupe mean
@Barbary Lion what does dedupe mean
calling it multiple times in the same route will not make multiple calls to the backend
emphasis on same route
with fetch, it dedupes throught the site, react cache dedupes on the route itself
@Arinji emphasis on **same route**
id say that can be missleading still, the emphasis is on same request/render
dont kys
@Arinji use unstable_cache
Barbary LionOP
const getGlobalMessages = async () => {
 return await db.query.globalMessage.findMany();
};
const getUserById = async (id: string) => {
 return await db.query.user.findFirst({
  where: eq(schema.user.id, id),
 });
};

const getMessages = async () => {
 const allGlobalMessages = await getCachedGlobalMessage();
 const usersMap = new Map();
 return Promise.all(
  allGlobalMessages.map(async message => {
   if (!usersMap.get(message?.createdBy)) {
    usersMap.set(message.createdBy, await getUserById(message.createdBy));
   }
   return {
    ...message,
    creator: usersMap.get(message.createdBy),
   };
  }),
 );
};

So in this should i put the unstable_cache only on getMessages, or getUserById and getGlobalMessages?
do it on get messages
actually wait
ok yea so cache getMessages @Barbary Lion
makes it so when you call getMessages multiple timees, its only called once.. but when it does go through, it gets fresh data
Barbary LionOP
nice, so the keyparts is options. Cause I can pass the revalidate
wha
you wont have keyparts as far as i can see
your funtion dosent look unique per user
@Arinji wha
Barbary LionOP
how i check that its working properly?@Arinji
@Barbary Lion how i check that its working properly?<@890486507872342027>
add a console.log inside your unstable_cache.

refresh your page 3 times, it should only appear once. (not thrice)
@ᴉuɐpɹɐɐ add a console.log inside your unstable_cache. refresh your page 3 times, it should only appear once. (not thrice)
Barbary LionOP
So per say when I submit a global message I submit a global message and revalidate the path, that revalidate the cache
yeah
Barbary LionOP
So what if idk 4 people write 1 message every 2 seconds, it's going to revalidate the cache 4 times and query the db 4 times?
no
invalidation doesnt cause query calls
invalidation just "marks" the data as invalidated
it only query the db when the data needs to be accessed
@ᴉuɐpɹɐɐ add a console.log inside your unstable_cache. refresh your page 3 times, it should only appear once. (not thrice)
Barbary LionOP
So if I put the console.log and write 3 messages in 3 seconds I should see 1 log?
Can't access my pc rn
if you put console.log and refresh the page 3 times, you should see 1 log
@ᴉuɐpɹɐɐ if you put console.log and refresh the page 3 times, you should see 1 log
Barbary LionOP
ok and its working as expected, and whenever a user submits a message the cache gets invalidated
@Barbary Lion Click to see attachment
Barbary LionOP
this is the maximum amout of optimization possible?
might add a message delay to avoid db calls 🫤
Cape lion
Hey there I am also using drizzle and currently opted out of cache via
export const revalidate = 0;
export const dynamic = "force-dynamic";

So will this cache function help??
Cape lion
It's related to cache only
but uh just to answer, react cache is for deduping
Cape lion
unstable_cache
Barbary LionOP
make your thread💀
Cape lion
Without cache also next caches the entire page right??
@Cape lion Without cache also next caches the entire page right??
no it wont, if you disable cache.. it will disable all cache
Barbary LionOP
will definitely add either pagination to messages or infinite scroll
mark a solution
Original message was deleted
boop
Barbary LionOP
sorry :blob_aww: