この
記事数が
最近は
PV の 集計方 法を ざっくり振り返る
PV 機能を
その
しかし、
現在は
Redis の
pageviews:${NODE_ENV}:${slug}の形式で キーを 保存している - インクリメント時は
IP アドレスを ハッシュ化して 保存し、 n 秒間重複して 計測されないように チェックしている - n 秒経過すると、
その キーバリューは 消滅する
キーに
PV の 多い 順に 取得する 方 法
人気記事を
- キーに
紐づく データを 全て 取得 ( mget)する sortで昇順に 並び替える
これだけ。
const getAllPageViewsSorted = async () => { const prefix = `pageviews:${env.NODE_ENV}:`; const keys = postMetadataForEdge.map(({ slug }) => `${prefix}${slug}`);
if (keys.length === 0) { return []; }
const values = await redis.mget<number[]>(...keys);
const pageViews = keys.map((key, index) => ({ slug: key.replace(prefix, ""), views: values[index] ?? 0, }));
pageViews.sort((a, b) => b.views - a.views);
return pageViews;};当初はscan コマンドをmget に
PV は
毎回 API が 走らないように する
PV は
import { unstable_cache } from "next/cache";
export const getCachedAllPageViewsSorted = unstable_cache( async () => getAllPageViewsSorted(), undefined, { revalidate: 60 * 60, },);キャッシュにはunstable_cache をunstable(不安定)と
unstable_cache を
キャッシュされた
話は
記事一覧を 表示
PV が
const popularPostCount = 6;
export const PopularPosts = async ({ className }: { className?: string }) => { const allPageViewsSorted = await getCachedAllPageViewsSorted(); const popularPosts = allPageViewsSorted .slice(0, popularPostCount) .map(({ slug }) => getPostBySlug(slug) as Post);
return ( <div className={cn( "grid grid-cols-2 gap-3 sm:grid-cols-3 xl:gap-4", className, )} > {popularPosts.map((post, index) => ( <div key={post._id} className="relative"> <ArticleCard post={post} /> <RankNumber rank={index + 1} /> </div> ))} </div> );};上記のslug
UI は

Data Cache の

さい ごに
人気記事を


