WebDesigner's Memorandumウェブデザイナーの備忘録

Obsidianを使った「自己流PKM」で行う知識トレーニング

この記事の要約
  • フォルダ構成は「Ideaverse」というVaultの構成を参考にしている
  • 基本的にはデイリーノートにメモをして、そこから派生させてノートを日々作っていく
  • テンプレートを活用してノートの作成や日々の情報収集をラクにしている

過去記事の『1つのノートアプリにすべて集約するのをやめた理由|2025年時点のノートアプリの使い分け』で、ObsidianをPKMとして使っていると紹介しました。

今回はその具体的な方法や考え方についてまとめます。

PKMとは何か?

PKMは「Personal Knowledge Management(個人の知識管理)」の略で、個人が持つ情報や知識を管理・活用するための概念や手法の総称です。

かなり広い概念ですが、単にメモを残しておくというよりも知識が体系化されていて、活用できる状態になっていることが重要です。

私がPKMを行う目的は「知識のトレーニング」

私がPKMを行うのは「知識のトレーニングを行うため」というのが主な目的です。
最近はAIに全部ノートを取ってもらっている人も見かけますが、私の場合は目的と合わせないのでそのような使い方はしていません。

筋トレをするのはダンベルを上げるのが目的なのではなく、ダンベルを上げて筋肉に負荷をかけ、筋肉を成長させるのが目的だと思います。
「このロボットアーマー着るとダンベル簡単に持ち上がるよ」と言われても……となります。

同じように私の場合のPKMを行う目的はノートを取る過程で自分の脳に負荷をかけ、知識の深掘りや記憶の定着を行いたいのが目的です。
「AIを使えばノートが大量生産できるよ」と言われても、それがしたいわけじゃないからな……となるわけです。

もちろん、人によっては自分が読んだ記事の内容を要約してまとめておいてもらい、そこから検索するといった使い方も有効だと思います。

このあたりを深く考えずに他の人の使い方を真似しても、やりたいことが実現できない可能性があります。
改めてノートを取って何をしたいのか?を考えてみるのも良いかもしれません。

ちなみに私の場合は目的に応じてノートアプリを完全に分けて考えています。
単に忘れないように書き捨て用のメモをしたいならUpNoteを使いますし、キレイにノートを取って情報を整理したいならNotionを使っています。

この辺りの使い分けに関しては、過去記事の『1つのノートアプリにすべて集約するのをやめた理由|2025年時点のノートアプリの使い分け』をご覧ください。

PKMの手法として有名なZettelkasten

Obsidianに限らず、最近のリンクによってノートを関連付けて管理していくタイプのノートアプリとセットで語られることが多い考え方に「Zettelkasten(ツェッテルカステン)」があります。

もともとはアナログの知識管理方法で、複数のカード箱にメモを入れて相互にリンクさせながら管理していく方法だったんだそうです。

アナログだとかなり手間がかかりそうですが、デジタルノートアプリが発展したことで、細かい単位でノートを作ってリンクでつなぐことが比較的簡単にできるようになりました。

PKMの手法や考え方には他にもさまざまな用語や考え方があるのですが、ややこしくなるので最初は「細かい単位でノートを作る」「関連ノートをリンクでつないで管理する」くらいを抑えておくのが良さそうです。

Obsidian

さて、PKMは情報や知識を管理・活用できればツールはなんでもいいわけですが、それでもObsidianがPKMツールとしてよくあげられます。

その理由は大きく3つあると思っています。

知識や情報のネットワークを構築しやすい

1つは知識や情報のネットワークを構築できることです。
Obsidianではリンクによってノートを繋げて、ネットワークのようにノート間のつながりを表現できます。

また、Obsidianではファイル名がノートのタイトルとして扱われるのですが、リンク切れ問題の対処として、ファイル名を変更すると自動的に他ノートに記載されているリンクも自動で更新されるようになっています。

わざわざリンクを修正して回る必要がありません。

Markdown ファイルとしてローカル環境で管理できる

2つ目はMarkdownファイルとしてローカル環境で管理できることです。
Obsidianのノートは「Vault」というローカルの保管庫内で管理されます。

普通のノートアプリは、NotionならNotion上でしか開けませんし、サービス側の都合で仕様が変わったり、最悪サービス終了したら別サービスへ移行が必要になります。
しかし、Obsidianの場合は極端な話、Obsidianアプリではなく他のMarkdownエディタで開けます。

Vault(保管庫)は私の場合Dropbox上に作成しているので、「知識を管理する」という観点から言っても、自分がファイルを保持できるのはありがたいです。

そしてこの特徴が、近年は別の形のメリットにもなっています。
ローカルのMarkdownファイルだからこそ、Visual Studio CodeやCursorなどのエディタ、Claude CodeやCodexなどを使って、AIでノート編集をできるというメリットになっています。

無料で利用できる

他にもリンクによるネットワーク型のノートアプリはいくつかありますが、有料のサービスが多いです(中にはサブスクリプションモデルのサービスもあります)。

また、ノートをリンクで関連付けていくということは、それなりにノート数が必要です。
ノート数が少ないとそもそも関連付け先のノートが少ないという事象が起こってしまいます。

ある程度のノート数までいくためには時間がかかるため、効果を実感するためには数ヶ月使って見る必要があると思います。

仮にそうでなかったとしても、そもそも長く使っていくことを考えたときに、無料で利用できるのは大きなメリットです。

フォルダ構成

フォルダ構成は「Ideaverse」というセットの構成を参考にし、そこから自分なりに使いやすいように変更しています。

私が本格的にPKMを始めたのが2024年の1月からなのですが、その前の2023年に色々と試行錯誤していた時期があります。

いくつかやり方を試した中で、2023年の9月から無料配布されたIdeaverseが分かりやすく、私の中でハマったのでそれ以来この構成を使っています(ただし、自分なりにカスタマイズはしています)。

Ideaverseは「Linking Your Thinking(LYT)」 というブランドでObsidianのトレーニングなどを発信・提供しているNick Milo氏が配布しているVaultです。
考え方のNotetakingではなく、Notemakingというのもしっくりきました。

「Ideaverse Pro」という有料版もあるのですが、金額がかなり高いので無料の「Ideaverse」をオススメします。

フォルダ構成は下記の通りです。

  • 「+」フォルダ
  • 「>」フォルダ
  • 「Atlas」フォルダ
  • 「Calendar」フォルダ
  • 「Efforts」フォルダ

「+」フォルダ

「+」フォルダは新規ノートの作成場所です。
ノートを新規作成するときはこのフォルダに作成されるようにしています。

いわゆるInboxフォルダで、まずはここに未整理状態のノートが溜まっていくので、ある程度の形に整え、整理できたらAtlasの方に移動します。
(もしくは、やっぱり不要だと思ったノートは削除します)

「>」フォルダ

これはもともとIdeaveraseには存在しないフォルダなのですが、引用用の参考ノート置き場にしています。

私は基本的に自分の言葉で整理するようにしていますが、「この記事にこんなことが書いてあった」「この人もこう言ってる」みたいなことを引用するときのための一時ノート置き場として使っています。

使い終わったら削除するノート達なので、空なことが多いです。
「+」フォルダと混ざると探すのが面倒なのと、あくまで他者の意見置き場として区切りを作りたかったので別フォルダにしています。

フォルダ名はMarkdown記法で一般的に引用記号として使われる「>」にしています。

「Atlas」フォルダ

Atlasには整形したノートやMOC(Map of Contentsの略で、リンクをまとめたノート)、テンプレートや画像などの素材類を入れておくフォルダです。

Atlasの中でさらにフォルダが分かれていて、下記のようになっています。

  • Maps:MOC置き場
  • Notes:ノート置き場
  • Special:Excalidrawなどプラグインを使うなどして作成した特殊なノート置き場
  • Utilities:テンプレートや画像置き場

ちなみにZettelkastenをやっている人は、この「Atlas/Notes」が「Permanent Note」と同じだと思ってもらえれば大丈夫です。

「Calendar」フォルダ

Calendar配下にはデイリーノートが格納されています。
「2026/01/2026-01-01」のように、年・月ごとのフォルダの中にデイリーノートが作成されます。

デイリーノートに関しては後ほど説明しますが、毎日Obsidianを起動すると作成されるノートで、ショートカットキーで開くように設定できます。
私の場合はcommand + D (Dailyの頭文字)で今日のデイリーノートが開きます。

「Efforts」フォルダ

Effortsはプロジェクト用のノート置き場と思ってもらえれば分かりやすいです。
そして下記4つのフォルダにプロジェクトノートを振り分けることで、優先度の整理を行います。

  • On
  • Ongoing
  • Simmering
  • Sleeping

私の場合はこれに終了済みの「Archive」を追加したりもしました。
「Sleeping(睡眠中)」と終了済みは意味が違うかなと思い、一応分ける目的で追加しました。

しかし、現在はこのEffortsフォルダはほとんど使っていません。
日々のプロジェクト管理など、情報をキレイに整理して活用するのはNotionを使っているからです。

人によってはEffortsからノート作りにつなげる人もいそうです。

作成するノートの種類

フォルダ構成が分かった次は、実際にどんなノートを作成するのかについてです。

Obsidianで作成するノートにはいくつか種類があります。
Ideaverseでは特に紹介されていませんでしたが、私なりに整理してみます。

  1. デイリーノート
  2. 名詞ノート
  3. 思考ノート
  4. 比較ノート
  5. MOC (マップノート)

1. デイリーノート

デイリーノートは日々作成する起点となるノートです。
Obsidianの標準プラグインでも作れますし、私の場合は「Periodic Notes」というプラグインで作成しています。

「Daily Note Template」でテンプレートを設定することで、デイリーノート作成時に自動でフォーマットを適用してくれますし、なんと起動時にJavaScriptを動かすことができます。

それを利用して、あらかじめ設定したRSSの1日前の更新情報をリンク一覧として表示されるようにしています。

実際に作成されるデイリーノートが下記です。

大きく3つのセクションに分かれています。

  1. Notes
  2. Memo
  3. Link

Notesセクション

Notesセクションでは、「Pickup」と「Today’s Action」があります。

「Pickup」は、過去に作成して最終更新日が1年以上前のノートをランダムでピックアップするようにしています。
目に触れることで「そういえばこんなのあったな」と改めて読んでみて、内容を更新したりリンクをつないだりしています。

「Today’s Action」には、今日作成したノートや今日更新したノートが一覧で出るようにしています。

このようにノートを一覧で表示するには、「Dataview」プラグインを使用します。
プラグインをインストールして下記のように記述すると、SQLのような感覚で指定フォルダから条件に合うノートを取得して一覧表示できます。

``` dataview
TABLE WITHOUT ID
file.link as ""
FROM "+" OR "Atlas/Notes" OR "Atlas/Maps"
WHERE file.cday = this.file.day
SORT file.ctime desc
LIMIT 20
```

「Today’s Action」が2列になっているのは、「Multi-Column Markdown」プラグインで2列表示できるようにしています。
最初は1列だったのですが、それだと流石に縦に幅を取るので2列にしました。

そして一覧の回りを囲っている枠は「Callout Manager」というプラグインで装飾した「コールアウト」と呼ばれる機能です。

下記のような記述で簡単に囲み枠の装飾ができます。

[!Note] ここにタイトル
> 本文を書く

Memoセクション

Memoセクションは好きにメモしていい場所として用意しています。
業務中や勉強中に気になったキーワードや思いついたことを箇条書きでメモしていきます。

ObsidianではWiki Linkに対応しているので、ノートを作成したくなったら[[ノートタイトル]]でリンクを作成してクリックすると新規ノートが作成できます。

基本的にデイリーノートを開いてメモをしたりして、思いついたことがあればノートを作成する(ノートは「+」フォルダに作成される)。
そして整理が終わったら「+」から「Atlas/Notes」に移動するといった流れでノートを増やしています。

もちろん既に作成済みのノートにリンクすることもありますし、そこから思わぬ気づきにつながることもあります。

Linkセクション

Linkセクションは記事などのリンクをまとめておく場所です。
全部で4つの項目があります。

  • Bookmark:手動で自分がリンクを貼る場所
  • Update:プラグインやライブラリ、言語仕様やサービス公式のブログなど、技術情報のアップデートに関連するリンク
  • Keep up:更新を追っている技術ブログなどのリンク
  • Gallery:更新されたギャラリーサイトのリンク

Bookmark以外はRSSフィードから自動的に1日前のリンクが生成されるようにしています。1日前の理由は、デイリーノートを作成するタイミングでJavaScriptが発火するからです。

例えば1月2日の朝9時にデイリーノートを作成した場合、9時以降の更新はデイリーノートに反映されません。
そのため、1月2日に作成したときに1月1日の記事を取得して表示することで、抜け漏れなくリンクが表示されるようにしています。

1日遅れたところで問題はないですし、ちゃんとキャッチアップすることが大事だと思っているのでこの方法を取っています。

ちなみに、普通にローカルだけでRSSをJSON変換して取得しようとするとCORSエラーに引っかかってしまうため、RSSからJSON形式に変換して返すプロキシサーバー的なものを用意しています。

作成はExpressというNode.jsのフレームワークを使用し、envファイルにRSSのURLを入れて管理しています。
個人で使うこと目的なのでかなり雑な作りになっていますが、クエリにグループ(update / keepup / gallery)と日付を入力すると、対象のリンクがJSON形式でまとまって返ってくるので、それをもとに一覧を作成しています。

わざわざ自分でその辺を作成するのが面倒であれば、Feedlyの有料プランで使えるFeedly APIを使えば同じことができるようです。

他にも「RSS to JSON」というぴったりなサービスもありますが、無料プランだと登録できるフィード数が25件だったため諦めました。

2. 名詞ノート

「Obsidian」「ノート」「PKM」のようなノートタイトルが名詞になるノートを名詞ノートと勝手に呼んでいます(私独自の呼び方です)。

新規ノートには「概要」という見出しが自動で作成されるようにしているので、そこにその名詞の概要をリスト形式でまとめます(基本的にノートはリスト形式で書くようにしています)。

いろんな名詞に対して、自分なりの言葉で説明することになるので理解が深まったり「あれ?この言葉についてちゃんと説明しろって言われると難しいな」と発見があります。

注意点として、Obsidianでは同じ階層に同じノート名を作成できないことがあげられます。
これはObsidianがローカルPCに実ファイルを作成するためです。

1単語1ノートで済めばいいですが、実際アプリやサービス、技術によって同じ名前でも概念が全然違う名詞があると思います。
例えば、「Yarn」はパッケージマネージャーのYarnもありますし、HadoopエコシステムのYARNもあります。

そんなときは「alias」というプロパティを使います。
ノートタイトルを「パッケージマネージャー:Yarn」のようにして、aliasに「yarn」などの表記を入れておきます。

こうすると、普通に検索のときにaliasに入れた内容でも引っかかるようになります。

他にも「/(スラッシュ)」記号が使えないなど、実ファイルを作成するが故にタイトルにいくつか制限があります。
「TCP/IP」というノートを作成したいのに、スラッシュが使えない場合は「TCP・IP」と入力しておいて、aliasで「TCP/IP」を登録します。

これで正しい表記でノートを検索できるようになります。
あとは名詞ノートを増やして関連するノートをつなげ、理解を深めていきます。

説明の中で別の名詞が出てくるときは[[ノートタイトル]]でリンク化したり、作成済みのノートもどんどん作ります。
[[]]の状態で真ん中にカーソルがあると、ノート検索用のポップアップが表示されるのでそこから検索してリンクすることも可能です(ここでもaliasに設定した表記で検索できます)。

3. 思考ノート

名詞ノートと違い、考えを整理するためのノートです。
ノートタイトルは「Obsidian:活用方法」のような名前になります。

そして「Obsidian」名詞ノートからリンクを繋げます。
基本的に先に名詞ノートがあって、そこからのさらに深い思考のために使います。

わざわざノートを分ける理由は、ノートの埋め込みがしやすくなるからです。
Obsidianでは「[[ノートタイトル]]」でリンクになりますが、先頭に!を付けて「![[ノートタイトル]]」とすると、ノートの埋め込みができます。

4. 比較ノート

複数の名詞の比較をするためのノートです。
ノートタイトルは「npmとBunの比較」のようになります。

思考ノートと同じく、分ける理由は埋め込みによるノート管理がしやすくなるからです。
例えば「npm」ノートと「Bun」ノートの両方に「![[NotionとObsidianの比較]] 」を記載して埋め込むことで、このノートを1つ変更すれば、埋め込んでいるノート両方に反映できます。

埋め込むと下記のように左側に線の装飾が表示されます。

Atomic Notesなんて言い方をするようですが、このようにノートを細かいトピックで区切っておくと、あとで埋め込むときに便利ですし、検索するときにも便利です。

ノート埋め込み時の工夫

また、細かいですが実際に埋め込むときには下記のようにしています。

![[npmとBunの比較#概要|n-h2]

最後に「#概要」とすることで、あとで概要以外に見出しが増えたとしても、概要部分だけが埋め込まれます。
そして「|(バーティカルバー)」以降ですが、この記号は本来リンクのテキスト部分を別のテキストに置き換えるために使います。

先ほどの「TCP/IP」ノートの場合、実際のノートタイトルは「TCP・IP」なので、リンクも「TCP・IP」になっていまいますが、「[[TCP・IP|TCP/IP]]」と書くことで、「TCP/IP」のリンクテキストを作れます。

本来の使い方と違うのですが、埋め込みの場合はここに入力した内容が .internal-embedalt属性で入ることに気付きました。

その仕組みを利用して、「n-h1」が入っていたら埋め込み内のh1を削除するといったCSSを追加で読み込ませています。

CSSはObsidianの環境設定の[外観]にある「CSSスニペット」で追加・管理できます。

記述しているCSSは下記の通りです。

.embed-title.markdown-embed-title{
    display: none;
}
.internal-embed[alt*="n-h1"].markdown-embed h1,
.internal-embed[alt*="n-h2"].markdown-embed h2,
.internal-embed[alt*="n-h3"].markdown-embed h3,
.internal-embed[alt*="n-h4"].markdown-embed h4,
.internal-embed[alt*="n-h5"].markdown-embed h5,
.internal-embed[alt*="n-h6"].markdown-embed h6 {
    display: none;
}
.internal-embed.markdown-embed ul {
    margin: 1em auto;
}

これで埋め込みもキレイにできるようにしました。

5. MOC

MOCは「Map of Contents」の略で、個々のノートをリンクでまとめた一覧・索引用のノートです。
ある程度ノートが増えてくるとごちゃついてくるので、リンクだけをまとめたノートを作成することで整理します。

このMOCを作るときに一気に知識が定着するように感じます。
いままでバラバラに作っていたノートがリンクで紐付いて整理されますし、MOCを作ることで「そういえばこのノートも必要だな」と気付いてノートを追加することもあります。

例えばObsidianのプラグインについてある程度ノートを作成したら、「Obsidianプラグイン」というノートを作成して、そこに各ノートへのリンクをまとめていきます。

ただ、私の場合は完全なMOCは少なく、名詞ノートと兼用することが多いです。
「概要」見出しとは別に「一覧」見出しを追加し、一覧にリンクを書いていきます。

完全にリンクだけのMOCもいくつかあり、それは「Atlas/Maps」フォルダにまとめています。
Mapsの中にいくつかフォルダがあり、そのフォルダの中にMOCが入っています。
「JavaScript」「PHP」「AI Service」など、言語やあまりにも広い概念はこのMaps内におき、勝手に「トップレベルMOC」と名付けています。

最終的にトップレベルMOCには体系的にリンクがまとまり、各名詞ノートにも関連するノートへのリンクが一覧で並んでいって、ノートが相互にリンクし合って知識のネットワークを作っていきます。

ノートテンプレート

ここからはノートのテンプレートを紹介します。
「Templater」というプラグインで、基本ノートのテンプレートが適用されるようにしています。

デイリーノートに関しては、「Periodic Note」というプラグインで設定可能です。

基本のノートテンプレート

下記のテンプレートを基本としています。
新規ノートを作成すると、単にフォーマットを揃えるだけではなくJavaScriptで少し処理をしています。

<%*
async function getLastOpenFile(){
    const lastActiveFile = app.workspace.lastActiveFile;
    if (tp.file.title.includes("無題のファイル")) {
        return "";
    }
    const lastFile = app.workspace.recentFileTracker.lastOpenFiles[0];
    const lastNameParts = lastFile.split("/");
    const fileName = lastNameParts.pop();
    const name = fileName.replaceAll(".md", "");

    const datePattern = /^\d{4}-\d{2}-\d{2}$/;
    if (datePattern.test(name)) {
        return "";
    }
    if (lastActiveFile !== null && lastActiveFile.basename !== tp.file.title ) {
        const lastActiveFileBaseName = lastActiveFile.basename;
        return `"[[${ lastActiveFileBaseName}]]"`;
    }
    return `"[[${name}]]"`;
}
function getAliasFromTitle() {
    const title = tp.file.title;
    const parts = title.split(":");
    if (parts.length > 1) {
        return parts[1].trim();
    }
    return "";
}
-%>---
up: <% await getLastOpenFile() %>
related: 
created: <% tp.date.now("YYYY-MM-DD") %>
tags: 
aliases: <% getAliasFromTitle() %>
---
## 概要

- 

やっていることは下記の通りです。

  • 直前に開いていたノートをupプロパティに自動でリンクとして入れる
  • 今日の日付をcreatedプロパティに入れる
  • ノートタイトルに「:」が含まれている場合、「:」以降をaliasesプロパティに入れる

upプロパティはそのノートの親を示すために使っています。
[[新規ノート]]」の形式でノートを新規作成した場合、直前に開いているノートが親の場合が多いので、自動的に入るようにしています(消すのは簡単ですが、追加は地味に面倒なのでこうしています)。

似たプロパティに「related」もありますが、これは親子ではなく関連ノートを示します。
そして「created」プロパティには今日の日付が入るようにします。

最後にノートタイトルに「:」が含まれている場合、「:」以降をaliasesプロパティに入れるようにもしています。
思考ノートや比較ノートを書くときや、名詞が被って先頭に別の言葉を入れるときにも「:」を区切りに使うようにしているので、後ろの方をaliasesとして自動で登録するようにしています。

このように、本文以外はできる限り都度登録しなくて済むようにしています。

デイリーノートテンプレート

デイリーノートテンプレートは下記の通りです。
基本的には「作成するノートの種類」見出しで説明したことを実現するためのコードになっています。

<%*
const title = tp.file.title;
const dateFormat = 'YYYY-MM-DD';
const dateMatch = title.match(/(\d{4}-\d{2}-\d{2})/);
let date = '';
if (dateMatch) {
    date = dateMatch[1];
}
%>---
created: <% date %>
tags:
  - Calendar
  - Calendar/Daily
---
<%*
function escapeMarkdownCharacters(text) {
    let cleanedText = text.replace(/[\n\r]/g, '');
    const escapeChars = /([#$$$$()])/g;
    return cleanedText.replace(escapeChars, '\\$1');
}
async function fetchArticlesFromFeeds(feedUrls) {
    let allFeedsContent = "";
    for (const url of feedUrls) {
        const response = await fetch(url);
        const json = await response.json();
        console.log('json');console.log(json)

        if (json && json.length) {
            json.forEach(feedItem => {
                let isTitleFlg = true;
                const escapedFeedTitle = escapeMarkdownCharacters(feedItem.title);

                feedItem.items.forEach(item => {
                    if (isTitleFlg) {
                        allFeedsContent += `- ${escapedFeedTitle}\n`;
                        isTitleFlg = false;
                    }
                    const escapedItemTitle = escapeMarkdownCharacters(item.title);
                    allFeedsContent += `    - [${escapedItemTitle}](${item.link})\n`;
                });
            });
        }
    }

    return allFeedsContent;
}

const officialRssUrls = [
    `{{RSS取得用のAPIサーバーURL}}/api/feed/?group=update&date=${date}`
];
const officialFeedContent = await fetchArticlesFromFeeds(officialRssUrls);

const rssUrls = [
    `{{RSS取得用のAPIサーバーURL}}/api/feed/?group=keepup&date=${date}`
];
const feedContent = await fetchArticlesFromFeeds(rssUrls);

const galleryRssUrls = [
    `{{RSS取得用のAPIサーバーURL}}/api/feed/?group=gallery&date=${date}`
];
const galleryFeedContent = await fetchArticlesFromFeeds(galleryRssUrls);

console.log(feedContent);
-%>
## Notes
### Pickup
> [!Note] Created
> ```dataviewjs
> const cutoff = DateTime.now().minus({ years: 1 }).startOf("day");
> const files = dv.pages('"Atlas/Notes"').file.where(f => f.mday && f.mday.toMillis() < cutoff.toMillis());
> const randomFiles = Array.from(files).sort(() => 0.5 - Math.random()).slice(0, 10);
> dv.table(["File", "Last Modified"], randomFiles.map(file => [file.link, file.mday]));
> ````
### Today's Action
>[!multi-column]
> >[!Note] Created
> > ``` dataview
> > TABLE WITHOUT ID
> > file.link as ""
> > FROM "+" OR "Atlas/Notes" OR "Atlas/Maps"
> > WHERE file.cday = this.file.day
> > SORT file.ctime desc
> > LIMIT 20
> > ```
>
> >[!Note] Modified
> > ``` dataview
> > TABLE WITHOUT ID
> > file.link as ""
> > FROM "+" OR "Atlas"
> > WHERE file.mday = this.file.day and file.cday != this.file.day
> > SORT file.mtime desc
> > LIMIT 20
> > ```

---
## Memo

- 

---
## Link
### Bookmark

- 

### Update

<% officialFeedContent %>

### Keep up

<% feedContent %>

### Gallery

<% galleryFeedContent %>
  • タイトルから日付を取り出してcreatedプロパティにセットする
  • タグに「Calendar」「Calendar/Daily」をセットする
  • Dataview / DataviewJS で 「過去ノートのランダム表示」「今日作成/更新したノート一覧」 を表示する
  • 指定したAPIからその日付のリンク一覧を取得して、Markdownの箇条書きを生成する

RSSからJSONに変換するAPIサーバーの作成

RSSからJSONに変換するAPIサーバーはExpressというNode.jsのフレームワークを使用しています。

とりあえず動けばいいやでかなり雑に作ったのですが、参考になるかもしれないのでコードを置いておきます。

const express = require('express');
const Parser = require('rss-parser');
const moment = require('moment');
const dotenv = require('dotenv');
const cors = require('cors');

dotenv.config();

const app = express();
const parser = new Parser();
app.use(cors());

const envList = (key) => {
  const v = process.env[key];
  if (!v || typeof v !== 'string') return [];
  return v
    .split(',')
    .map(s => (s || '').trim())
    .filter(Boolean);
};

const feedGroups = {
  update: envList('UPDATE_FEEDS'),
  keepup: envList('KEEPUP_FEEDS'),
  gallery: envList('GALLERY_FEEDS'),
};

app.get('/', async (req, res) => {
  const group = req.query.group;
  if (!group || !(group in feedGroups)) {
    return res.status(400).json({ error: 'Invalid or missing group parameter' });
  }

  const feedUrls = feedGroups[group] || [];
  const rawDate = req.query.date;
  const parsedDate = rawDate && moment(rawDate, moment.ISO_8601, true).isValid()
    ? moment(rawDate)
    : moment();

  const startOfDay = parsedDate.clone().subtract(1, 'days').startOf('day');
  const endOfDay   = parsedDate.clone().subtract(1, 'days').endOf('day');

  try {
    // URLが空なら即空配列を返す
    if (feedUrls.length === 0) {
      return res.json([]);
    }

    const results = await Promise.allSettled(
      feedUrls.map(async (url) => {
        try {
          if (!url || !/^https?:\/\//i.test(url)) return null;
          return await parser.parseURL(url);
        } catch (err) {
          console.error(`Error parsing URL ${url}:`, err);
          return null;
        }
      })
    );

    const filteredItems = results.reduce((acc, r) => {
      if (r.status !== 'fulfilled') return acc;
      const feed = r.value;
      if (!feed || !Array.isArray(feed.items)) return acc;

      const items = feed.items.filter((item) => {
        const dateStr = item?.pubDate || item?.isoDate || item?.date;
        const d = dateStr ? moment(new Date(dateStr)) : null;
        return d && d.isValid() && d.isBetween(startOfDay, endOfDay, undefined, '[]');
      });

      if (items.length > 0) {
        acc.push({
          title: feed.title || '(no title)',
          items,
        });
      }
      return acc;
    }, []);

    return res.json(filteredItems);
  } catch (err) {
    console.error('Unexpected error handling feeds:', err);
    return res.json([]);
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

.envファイルで下記のようにカンマ区切りでRSSのフィードURLを記述して管理します。

UPDATE_FEEDS=https://〇〇/blog/rss.xml,https://〇〇/blog/rss.xml
KEEPUP_FEEDS=https://〇〇/blog/rss.xml
GALLERY_FEEDS=https://〇〇/blog/rss.xml

画像の利用について

私の場合画像を利用することはほとんどありません。
どうしても必要な場合はGyazoを使っています。

Obsidianは他のノートアプリと違い、すべてのファイルをローカルで管理するため、ノート内に画像を貼ると、その画像はあらかじめ指定しておいたフォルダ内に格納され、その画像ファイルへのリンクとして埋め込まれます。

画像の管理が面倒ですし、図が欲しいときはMermaid記法で記述しています。
どうしても画像を貼りたい場合だけGyazoにアップしてGyazoのリンクを貼っています。

スマホアプリの利用について

私の場合、スマホアプリでObsidianのノートを書くことは稀です(ほとんど使わない)。
iPadでたまに書くかなというレベルです。

あくまで閲覧だけできるように、念のため「Remotely Save」というプラグインでDropbox経由で同期しています。

もし忘れないように一時的な書き捨てメモをしたい場合はObsidianではなくUpNoteを使用します。
なのでスマホでちょっとメモをしたいときに開くのはだいたいUpNoteです(スマホでも動作がかなり軽いのが魅力)。

あくまでObsidianは自分の知識を管理するためなので、使うのはそれなりに腰を据えて書くときだけになります。

Keyboard Maestroの活用

Keyboard Maestroを使うことで、Obsidianをさらに便利に使えます。
特にノートの埋め込みはよく使うので、これをショートカットキーでできるようにしています。

[[ノートタイトル]]形式のテキストをコピーした状態でcommand + Eを押すと、![[ノートタイトル#概要|n-h2]]に変換されます。

AIの活用

最初にも説明した通り、私がPKMを行うのは「知識のトレーニングを行うため」が主な目的です。
そのためAIを使ってノートを自動生成的なことはしていません。

改めてになりますが、筋トレをするのはダンベルを上げるのが目的なのではなく、ダンベルを上げて筋肉に負荷をかけ、筋肉を成長させるのが目的だと思います。
「このロボットアーマー着るとダンベル簡単に持ち上がるよ」と言われても……となります。

なので私がAIに求めることは「ここ負荷かかってないよ」「こうすればもっと負荷かかるよ」というコーチ的な役割です。

自分に足りない知識をAIに聞く

AIに聞いて私のObsidianの中で抜けがありそうな知識を聞きます。
これで抜けがある知識を深掘りしてノート化します。

自分の知識がObsidian上にどんどん溜まっていっているので、「今の自分に足りない知識って何?」「次に何を学べばいいと思う?」という聞き方ができます。
これで次に学ぶべきことの指針が立てられます。

AIでテスト作成

この辺りは比較ノートがあるとテストとしてうまく機能しそうです。
単純なテスト的なものはサクッと作れます。

他にもAnkiという単語帳アプリがあり、それを使うことで記憶の定着も図れます。
ただ、こちらはうまく活用しきれていません。

資格試験の勉強などであれば、普通に問題を解いて間違えた問題の復習用に使うの方が効果を実感できました。

ObsidianでPKMをしてよかったこと

最後にObsidianでPKMをした結果、何がよかったのかもまとめておきます。

知識の定着率が違う

人間の記憶はネットワークのように関係が構造化されている方が記憶しやすいそうです。
特にいまAWSの勉強をしているのですが、さまざまな用語の親要素は何なのか?関連要素は何なのか?が整理できると理解度が違います。

何かトピックを勉強するときも、包含関係を意識するようになります。
そして、関連する他の技術と「何が違うのか?」「この技術のメリットは?」と自分なりに考え、分からなければ調べて理解していけます。

新しいノートを作成するときも、「あの技術に似ているな」と思ってノートをリンクさせ、比較ノートを作成します。

更新前提のため、ラクに作成できる

PKMはノートをどんどん更新していきます。
そのため、最初から完璧でキレイなノートを作る必要はありません。

ノートによっては雑に一行自分で考えたひと言を書いてあるだけのノートも存在します。
それを何度も更新して、ときには削除して自分の理解度と一緒にノートを成長させていくようなイメージです。

また、自分の理解が不安なときはリストの先頭に「?」をつけて記載します。
「要するにこういうこと?」「合ってるか分からないけどこういうことっぽい」のような自信がない内容をこの書き方で記述します。

「List Callouts」というプラグインを入れておくと、箇条書きに装飾を使用できるようになり、「?」付きのリストが作成できます。

まとめ

PKM自体は2024年の1月から実践しており、調べて自分なりに方法を模索し始めたのは2023年頃からになります。かれこれ2年以上続いています。

ある程度時間が経ってノートも増えてきたおかげで効果を実感できていますが、Obsidianはカスタマイズ性も高く、それがかえってノートに集中できない状態を生み出しそうな気もしています。

特にここまでやるのは非エンジニアの人にはハードルが高いように感じます(そこまでガチガチにやらなくて、単にリンクを貼っていくだけなら簡単に始められます)。

誰にでもオススメできるかと言われると悩みますが、この記事がこれから始めようとしている人の参考になれば幸いです。

著者について

プロフィール画像

サイトウ マサカズ@31mskz10

1997年生まれ。2016年から専門学校でデザインについて勉強。卒業後は神戸の制作会社「N'sCreates」にウェブデザイナーとして入社。このブログでは自分の備忘録も兼ねて、ウェブに関する記事や制作環境を効率的に行うための記事を書いています。

Twitterをフォロー Facebookでいいね