
Obsidianのプラグイン「Dataview」でScrapbox風の2ホップリンクを実現する
2ホップリンクとは
Scrapboxの2ホップリンク
ScrapboxからObsidianに切り替えると、2ホップリンクが欲しくなることがあります。
Scrapboxでは、現在のページからリンクしているページと、同じページにリンクしているページが表示されます。

上記は次の図のようにリンクしている状態です。この「note 2」から「keyword」にリンクがありますが、これが1つ目のホップです。同じように「note 1」や「note 3」、「note 4」からも「keyword」にリンクがある場合、「note 2」のページに他の「note 1」「note 3」「note 4」が関連するページである、としてリンクを表示することが2ホップリンクのしくみです。

Obsidianで2ホップリンク
Obsidianでは標準で「アウトゴーイングリンク」と「バックリンク」が用意されています。つまり、上記と同じような構成でファイルを作成した場合、「note 2」を開くと「keyword」が、「keyword」を開くと「note 2」が表示されます。
しかし、2ホップリンクは標準では用意されていません。
Obisidianには標準以外にもコミュニティプラグインという方法があり、実際に「2Hop Links Plugin」というプラグインが提供されています。
これを使うと、次のようにScrapbox風のリンクを表示できます。

Obsidianの2Hop Links Pluginの問題点
上記のように、Scrapbox風の2ホップリンクを実現できるのですが、以下の問題があります。
iOSアプリやiPadOSアプリで動かない
フロントマターで指定したタグでの2ホップリンクが表示されない
まずは1つ目の問題点です。ObsidianにはiPhoneやiPadで使えるモバイルアプリ「Obsidian Mobile」が提供されています。
しかし、上記の「2Hop Links Plugin」はiOSアプリやiPadOSアプリでは動作しません。
つまり、現状ではモバイルアプリで2ホップリンクを表示できないのです。
2つ目の「タグ」については、Scrapboxではタグとリンクが同じ意味を持っています。つまり、ページ内にタグの形で記述すると、そのタグについても2ホップリンクが作成されます。

上記の「2Hop Links Plugin」でも、本文中でタグを指定した場合には問題なく2ホップリンクが表示されるのですが、フロントマターでタグを指定した場合、2ホップリンクが表示されません。

もちろん、このプラグインに対して修正のプルリクエストを出す方法もありますし、新たにプラグインを作る方法もあるのですが、ここではObsidianで人気のプラグインである「Dataview」を使ってみます。
Dataviewプラグインの使い方
このプラグインでは、SQLのような構文でObsidianをデータベースのように使ってリストやテーブルを表示できます。たとえば、次のように書けば、フロントマターと本文中のどちらでも「keyword」というタグをつけた記事へのリンクのリストが表示されます。
```dataview
list from #keyword
```

さらに、JavaScriptを使って、条件に合うものを抽出することもできます。
JavaScriptで処理するには、Dataviewプラグインの設定画面から「Enable JavaScript Queries」というオプションをオンにしておきます。

バックリンクを実装する
実際に2ホップリンクを作る前に、まずは簡単にバックリンクを実装してみましょう。ノート内に以下の記述をします。
```dataviewjs
dv.list(dv.current().file.inlinks.sort());
```
最初の行はDataviewのJavaScriptの記述だと指定しています。
そして、続く行でバックリンク(他のノートからのリンク)のリストを作成しています。
もう少し詳しく解説すると、「dv.list」というのはDataviewのリストを作成する処理です。括弧内の「dv.current()」は現在のノートのオブジェクトを表し、その後の「file.inlinks」で他のノートからのリンクを取得します。
最後に「sort()」はJavaScriptのソート(並べ替え)関数です。これで、バックリンクについて、ファイル名の名前順に並べたリストができます。
2ホップリンクを作成する
アウトゴーイングリンク(他のノートへのリンク)は本文中にもありますので、2ホップリンクを作成してみましょう。
2ホップリンクは、アウトゴーイングリンクを調べて、そのページに対するバックリンクを調べれば作成できます。
たとえば、次のように記述できます。
```dataviewjs
for (let outgo of dv.pages('outgoing([[' + dv.current().file.name + ']])')) {
dv.header(3, outgo.file.name);
dv.list(outgo.file.inlinks.sort());
}
```
最初のfor文で、アウトゴーイングリンクの一覧を取得し、1つずつ繰り返しています。
そして、2行目ではそのファイル名で見出しを作成しています。この「dv.header」関数は1つ目の引数で見出しの大きさを、2つ目の引数で見出しの文字を指定しています。
3行目は上記のバックリンクを作成したものと同様です。
タグでの2ホップリンクを作成する
タグであっても通常のリンクと考え方は同じです。しかし、タグの場合はバックリンクという考え方がありません。
そこで、そのタグを含むファイルの一覧を取得します。
たとえば、次のような感じです。
```dataviewjs
for (let tags of dv.current().tags) {
dv.header(3, "#" + tags);
dv.list(dv.pages("#" + tags).file.link);
}
```

ただし、タグが設定されていないページではエラーになります。
このため、タグが設定されているか、事前に存在チェックをしておくとよいでしょう。
```dataviewjs
if (dv.current().tags) {
for (let tags of dv.current().tags) {
dv.header(3, "#" + tags);
dv.list(dv.pages("#" + tags).file.link);
}
}
```
ここではリストで作成しましたが、ファイル名以外も表示したい場合、テーブル形式の方がわかりやすい場合もあります。たとえば、ファイルにエイリアスを設定している場合です。
この場合、次のように書くとよいでしょう。
```dataviewjs
if (dv.current().tags) {
for (let tags of dv.current().tags) {
dv.header(3, "#" + tags);
dv.table(["link", "aliases"],
dv.pages("#" + tags).file
.sort(k => k.link).map(b => [b.link, b.aliases]));
}
}
```

まとめ
上記のような方法で、Scrapboxと似たような2ホップリンクを実現できます。もちろん、厳密には同じではありませんし、デザイン面ではもう少し工夫した方がいいかもしれません。
また、すべてのページで表示するには、各ページに上記のスクリプトを埋め込む必要があります。
このような問題はありますが、もし一時的に2ホップリンクの内容を確認したいだけであれば、上記のようなスクリプトをテンプレートに登録しておき、確認後に削除するような使い方が便利でしょう。
なお、Obsidianでタグを使用する場合には、以下の記事で書いた特徴に注意しましょう。