「新しい順」だけでは足りなかった。記事の並び順を考える
このブログで、グリッチハンターの記事をピン留めしてほしいと頼んだあと、「先頭になってない」と伝えたことがある。
記事のデータにピン留めの印を付けることと、画面の先頭へ並べることは、別の処理だった。記事を増やしながら、何を基準に並べるかも決める必要が出てきた。

画像:このサイトのTOP。9月16日付のピン留め記事が、9月18日付の記事より前に並んでいます。
「新しい」は、どの日付なのか
記事には、公開日と更新日がある。
公開日は、その記事として付けている日付。更新日は、公開後に内容を更新したときに持たせる値だ。このサイトでは、ビルドしただけで記事の更新日を書き換えることはしていない。
TOPに使う記事の取得処理では、更新日があれば更新日を、なければ公開日を比較している。
const aTime = (a.data.updateDate ?? a.data.pubDate).getTime();
const bTime = (b.data.updateDate ?? b.data.pubDate).getTime();
return bTime - aTime;たとえば、昨日公開した記事と、先月公開して今日更新した記事があれば、この条件では後者が先になる。最近手を入れたものが上がる並べ方だ。
一方、記事の前後リンクを作る処理は、公開日を使っている。どの順番が正しいかは、一覧が何を伝えたいかによって変わる。
ピン留めは、日付より先に扱う
TOPでは、日付順に取得した記事を、さらにピン留めの有無で並べている。
const homePosts = [...allPosts].sort(
(a, b) => Number(Boolean(b.data.pinned)) - Number(Boolean(a.data.pinned)),
);ピン留めした記事を前へ出し、同じピン留め状態の記事同士では0を返す。現在のJavaScriptの安定ソートでは、比較結果が同じ要素の前後関係を保つため、先に作った日付順をそのグループ内で維持できる。Array.sortの説明
元の配列を直接変更しないように、TOP用には[...allPosts]でコピーしている。同じ記事データから月報や読書の一覧も作るので、TOPだけの並び替えとして扱える。
現在のルールをまとめると、こうなる。
| 優先順位 | 比較するもの |
|---|---|
| 1 | ピン留めしているか |
| 2 | 更新日。なければ公開日 |
| 3 | 上記が同じなら、取得時の順番を維持 |
日付を新しく書き換えて先頭に置くのではなく、最初に読んでほしいという指定を独立させている。
先に10件取ると、ピン留めが届かない
TOPの表示は最大10件だ。現在のコードでは、全記事を並べ替えたあとにslice(0, 10)している。
もし先に新しい記事を10件だけ取り、その中でピン留めを探す順番にすると、古いピン留め記事は候補にすら入らないことがある。
全記事を取得
→ 日付で並べる
→ ピン留めを先頭へ
→ 表示する10件を取り出すこれは現在の処理順の意味を説明したもので、以前「先頭になってない」と伝えたときの原因を、この一点に断定するものではない。
同じ日に3本書くと、同順位が増える
最近は、一日に複数の記事を作っている。日付を日単位で付けているので、同じ日に出す記事同士は、比較する値が同じになる。
TOPの日付比較は、その場合に0を返す。ただし、取得時の順番を保つことと、いつでも決まった記事を先にすることは同じではない。明確に揃えたいなら、同じ日時の場合の追加ルールが必要になる。
さらに、公開日順を作る別の関数を読むと、現在は次の比較になっていた。
return dateA > dateB ? -1 : 1;これだと同じ日付のAとBを比較しても1、BとAを比較しても1になる。比較関数として、同順位を適切に表していない。
今回、同じ日付を持つ二つの値でこの式を実行し、どちらの向きでも1になることを確認した。今のコードの課題として残っている。
改善するなら、まず日時の差を比較し、同じなら記事のslugなど一意な値で順番を決める方法がある。意図した掲載順が必要なら、専用の順序番号を持たせる選択肢もある。これは改善案で、この記事を書く時点では変更していない。
何を試せば、並び順を確かめられるか
並び替えを直すなら、次のような組み合わせを用意して確認したい。
- 古いピン留め記事が、新しい通常記事より前に出る。
- 更新日のある記事では、その日付が比較に使われる。
- 同じ日付の記事を複数渡しても、決めた順番になる。
- 11件以上の記事があっても、ピン留めを含む10件が出る。
- TOP用の並び替えで、ほかの一覧用の配列を変更しない。
単に新旧二つの記事を並べるだけでは、同じ日付や件数制限の問題は見つけにくい。自分が実際に使う「一日3本」という条件が、確認する例にもなる。
新しい記事を見せたい。最近更新した記事も読んでほしい。グリッチハンターは先頭に残したい。それぞれの希望を、データと比較の順番へ分けて書く必要があった。
記事を増やす作業には、記事の入口を整える作業も付いてくる。
この記事は、1ef515a時点のTOPと記事取得処理をCodexと確認した記録です。同日付の比較や順番の固定については、現状と改善案を分けて記載しています。