見出し画像

Notion で(自分なりの)タスク・時間管理を始めよう!(拡張編④)

前回は、ついに Google Apps Script(GAS)にまで手を出して、
Google カレンダーから「今日の予定」を取得し、タスクを自動生成させることも可能となりました。

ちょっと説明することが多すぎて、簡単に話を流してしまった部分も多々ありますが、とりあえず、全体の流れを把握してもらいたかったので、
ともあれ、一つの記事にまとめられたことには、個人的に満足しています。

特に、いちいち説明するのは面倒な、API の設定とかアクセス許可の話などを、一通り終えられたのは、かなり大きいですね。
まぁ、細かい話は、さらなる拡張を行いながら、少しずつ補足していくことにしましょう。

今回は、そろそろ「ルーチンデータベース」を導入したいところですが、
先に「セクション」もデータベースで管理して、プログラムから扱いやすいようにしておきたいと思います。


セクションデータベースを導入する

各セクションの名前や時間帯の設定が変わるたびに、プログラムを修正しにいくのは面倒なので、
例えば、次のような「セクションリスト」データベースを用意しておいて、プログラムからは、常にこのテーブルを参照するようにしましょう!

「セクションリスト」データベースを作成する

以前「プロジェクトリスト」を作成した時や「終了予定日時」の表示を作った時と似たような手順になるので、詳細は省きますが、

これで、今まで「セレクト」プロパティとして管理し、選択していたセクションを「セクションリスト」から選べるように、変更できます。

今回は「タスクリスト」データベース側で「セクション」プロパティの種類を「リレーション」に変えて、次のように設定しました。

「セクション」プロパティの種類を「リレーション」に変える

以前までの記事で追加してきた、他の「リレーション」と異なるのは、ここで「セクションリストに表示」をオンにしていない点で、
別にどちらでも良いとは思うのですが、各セクションに紐づくタスクは、日を跨いでどんどん増えていくため、
もちろん、運用にも寄りますが、おそらく、表示していても仕方がないという人が大半なのではないでしょうか?

ちなみに、セクションの名前に「S2.」などの番号を付けているのは、グループの「並べ替え」を考慮してのことですが、
まぁ、その辺は、自由にカスタマイズしてみてください。

グループの「並べ替え」を確認する

あと、朝は「趣味のアウトプット」を中心に行い、午前中には「重要度の高い仕事」を、午後には「重要度の低い仕事」をし、
夜にだけ「趣味のインプット」を行うように、セクション名からして促すという手法も、時間帯を使いこなせていない人には、結構、オススメです。

つまり、セクション選択の時点で、自然とゆるい強制力を働かせることができるというわけですね。

セクションデータを取得する

次に、いよいよ、Google Apps Script で「Notion のデータベースからデータを取得する方法」を、ご紹介いたしましょう。

新しいプロジェクトを作っても構いませんが、Google カレンダーの予定からタスクを自動生成する際にも、セクションを設定しておきたいので、
ここでは、前回のプロジェクトへ、コードを追記することにします。

まずは「セクションリスト」データベースのデータを Notion から取得できるかどうか、確認してみましょう!

function test() {
  const sections = getSections("xxxxx", "secret_XXXXX");
  console.log(sections);
}

function getSections(database_id, secret) {
  const data = { "sorts": [{ "property": "開始時刻", "direction": "descending" }] }
  const options = {
    'method': 'post',
    'headers': {
      'Authorization': 'Bearer ' + secret,
      'Content-Type': 'application/json',
      'Notion-Version': '2022-06-28'
    },
    'payload': JSON.stringify(data)
  };
  const response = UrlFetchApp.fetch('https://api.notion.com/v1/databases/' + database_id + '/query', options);
  const contents = JSON.parse(response.getContentText());
  const object = {};
  for (const result of contents.results) {
    object[result.properties["開始時刻"].rich_text[0].plain_text] = result.id;
  }
  return object;
}

実行するのは「test()」関数の方で、単に、その中で「getSections()」を呼び出してみて、新しい関数の動作をテストしている形です。

ここで、「getSections()」の引数の "xxxxx" については、前回「タスクリストデータベースの ID」を入れたのと同じ要領で、
今回は「セクションリストデータベースの ID」に置き換えてください。
シークレット "secret_XXXXX" の方は、前回と同じ値で良いと思います。

それでは、ページ上部のメニューで「プロジェクトを保存」し「実行する関数を選択」は「test」に切り替えてから「実行」ボタンを押してみましょう。

getSections() を利用して「セクションリスト」を取得する

実行ログに、何やら「謎の文字列」を含むオブジェクトが出力されましたでしょうか?

これは、タスクリストとセクションリストが「リレーション」で繋がっているためで、もし、タスクにセクションを設定したいなら、
タスクリストの「セクション」プロパティに入れるべきは、セクション名ではなく、各「開始時刻」に対応している「セクションの ID」だからです。

まぁ、よく分かっていなくても、ひとまず、同じように書いて先に進んでいけば、いずれ理解も追いついてくると思います。

逆に、プログラミングのできる人は、次のようなデータを送信して「結果を降順でソートしている理由」を、クイズだと思って考えてみてください。

{ "sorts": [{ "property": "開始時刻", "direction": "descending" }] }

セクションプロパティを設定する

では、Google カレンダーから取得した予定を、タスクリストに追加する際、セクションも自動で設定されるように、改良していきましょう。

色々とやり方はあると思いますが、ともかく「開始時刻を受け取り、該当するセクションの ID を返す関数」を、新たに作成しておくことにします。

function test() {
  const sections = getSections("xxxxx", "secret_XXXXX");
  console.log(time2section(sections, "12:34"));
  console.log(time2section(sections, "18:00"));
}

function time2section(sections, time) {
  const keys = Object.keys(sections);
  const start = keys.find(key => time >= key);
  return sections[start];
}

JavaScript の説明は省略しますが、簡単に言えば、降順に並べ替えた「各セクションの開始時刻」を、入力された時刻と一つずつ比較していって、
各セクションの内、最初に「入力の時刻以下になった時」の ID を取得するというのが「Array.prototype.find()」の役割です。

慣れていない人には、なかなか理解が難しいですかね?

そもそも、セクションリストに「終了時刻」プロパティも追加しておくという方法もあるのですが、おそらく、やること自体は大差ないと思います。

ともあれ、変更を保存して「test()」関数を実行した時、次のような結果が得られるなら、なんでも構いません。

time2section() 関数を追加する

これで、GAS から Notion へタスクを追加する際、セクションプロパティを設定する準備が整いました!

分かりやすさを重視するとすれば、以下のような感じになるでしょうか。

function postNotion(database_id, title, start, minutes, secret) {
  const sections = getSections("xxxxx", "secret_XXXXX");
  const time = start.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false });
  const section = time2section(sections, time);
  const data = {
    "parent": { "type": "database_id", "database_id": database_id },
    "properties": {
      "title": { "type": "title", "title": [{ "type": "text", "text": { "content": title } }] },
      "実行日": { "type": "date", "date": { "start": start } },
      "開始予定時刻": { "rich_text": [{ "type": "text", "text": { "content": time } }] },
      "セクション": { "relation": [{ "id": section }] },
      "見積値": { "type": "number", "number": minutes }
    }
  };
  const options = {
    'method': 'post',
    'headers': {
      'Authorization': 'Bearer ' + secret,
      'Content-Type': 'application/json',
      'Notion-Version': '2022-06-28'
    },
    'payload': JSON.stringify(data)
  };
  UrlFetchApp.fetch('https://api.notion.com/v1/pages', options);
}

これなら「postNotion()」に、少し追記するだけで済みます。

増えた処理としては、上で作った「time2section()」にセクションデータを渡すため、「getSections()」を呼び出しておいたり、
次のように、該当するセクションの ID を追加で送っているくらいです。

"セクション": { "relation": [{ "id": section }] }

ちなみに、効率を重視したい人は、予定の数が増えても「getSections()」関数の呼び出し回数は増えないように「myFunction()」の方へ移動させて、
例えば「sections」を「postNotion()」関数に引数として渡すようにするなどしてみてください。

まぁ、基本的に、寝ている間に自動実行される予定のプログラムなので、それほど気にする必要はないとは思いますが。

次回に続く

さて、ここまでで、「postNotion()」によって、「タスクリスト」データベースにタスクを追加する方法が分かっているのに加え、
例えば「getSections()」のように、Notion のデータベースからデータを取得する関数も作れるようになりました。

ということは、同様に「getRoutines()」関数を作り、ルーチンデータベースから取得したデータを元に、タスクを自動生成することもできるはずです!

しかし、実際に書いてみると、想定より長くなってしまったため、ルーチンリストの導入について説明するのは、やはり、次回にしたいと思います。

ではまた。

この記事が気に入ったらサポートをしてみませんか?