はじめに
グッドパッチで情報システム担当の@enpipiと申します。
2023年9月にNotionの関数に使える数式が大幅にアップデートされ今までできなかった表現ができるようになりました。 本記事では、数式2.0から登場した数式を用いて更新日の自動更新を実現します。
注意
関数はオートメーショントリガーに使えず、Zapierでも関数は拾えません。 リマインド通知やカレンダーに予定として入れたい場合はNotionのdatabase APIを使う必要があります。
概要
サービスの契約更新日などを把握しておきたいが、更新日を毎回入力するのが手間だったのでデータベースの関数を使って更新日を自動更新しました。
できたもの
今日の日付が契約日を過ぎていた場合に年次は一年後、月次は一ヶ月後を算出する。
できること
- 今日を起算日として次回更新日を自動で算出する
- 年次・月次を判定する
躓いたところ
例えば契約日が11/01だった場合、 day(prop"契約日")とすると、dd
(01)ではなくd
(1)で抽出されてしまうので、1/11と11/1が判別できません。そのため、formatDate
を使って dd
に整形する必要がありました。
手順
1. 適当なデータベースを用意して、プロパティに契約日を用意する
更新日の基準値としてなんでも良いので日付を用意します。ここではプロパティ名を契約日とします。
2. プロパティに年次・月次を追加
セレクトを使って年次・月次を追加。ここではプロパティ名は契約期間とします。
3. 関数を使って次回更新日を算出
関数として以下を入力。プロパティ名は更新日とします。
if( prop("契約期間") == "年次", if( 0 > toNumber(formatDate(prop("契約日"), "MMDD")) - toNumber(formatDate(now(), "MMDD")), (year(now()) + 1 + "-" + formatDate(prop("契約日"), "MM-DD")).replaceAll("-", "").parseDate(), (year(now()) + "-" + formatDate(prop("契約日"), "MM-DD")).replaceAll("-", "").parseDate() ), if( 0 > toNumber(formatDate(prop("契約日"), "DD")) - toNumber(formatDate(now(), "DD")), dateAdd( (year(now()) + "-" + month(now()) + "-" + formatDate(prop("契約日"), "DD")).replaceAll("-", "").parseDate(), 1, "months" ), (year(now()) + "-" + month(now()) + "-" + formatDate(prop("契約日"), "DD")).replaceAll("-", "").parseDate() ) )
ロジック
上のロジックは次のとおりです。 chatGPT に言語化してもらいました。
- 最初に、
if
関数で「契約期間」が「年次」かどうかを判断します。「契約期間」が「年次」の場合:
- 契約日と現在の日付を比較し、結果が0より大きい(契約日が本日より前)なら、現在の年と契約日を結合して更新日を設定します。
- 結果が0より小さい(契約日が本日より後)場合、現在の年に1足したものと契約日を結合して更新日を設定します。
「契約期間」が「年次」以外(たとえば「月次」)の場合:
- 契約日と現在の日付を比較し、結果が0より大きい(契約日が本日より前)なら、現在の年と月、契約日を結合して更新日を設定します。
- 結果が0より小さい(契約日が本日より後)場合、現在の年と月、契約日を結合した日付に1か月を足して更新日を設定します。
この関数中の
replaceAll("-","").parseDate()
は、日付形式を整形し、正常な日付として Notion に認識させるために使用しています。また、formatDate()
関数は、日付を特定のフォーマットに変換するために使用されています
[ オプション1 ] フィルター、ソートをかける
最後に表示するサービスを直近のものだけに絞る、更新日順にソートなどして完成です。
[ オプション2 ] Notion APIを使って通知する
Notion APIを使うことで特定のデータベースに対してフィルターやソートをかけて値を取得することができます。Zapierでは関数で生成した値は取得できませんがAPI なら取得できます。 ここでは、GASを使います。
Notion APIを利用するための準備
- 私のインテグレーション | Notion開発者へアクセスし、新しいインテグレーションを作成します。ここでは名前を「YearlyServiceRenewalAlert」としました。
- コンテンツ機能は「コンテンツを読み取る」、ユーザー機能は「ユーザー情報なし」とします。
- 「内部インテグレーションシークレット」を取得して保管しておきます。GASで利用します。
- データベースのIDを取得します。対象のデータベースのURLからデータベースIDを確認しましょう。
https://www.notion.so/<データベースID>?v=<ビューID>
のようになっています。
- インテグレーションからデータベースを参照できるようにします。
- データベースページの右上の︙をクリック
- Add Connections
- YearlyServiceRenewalAlertを選択しましょう。
Notion APIを使って望む値を取得する
Query a databaseを使います。
このAPIはインテグレーションされたデータベースのレコードをフィルターして取得することができます。
const NOTION_API_KEY = PropertiesService.getScriptProperties().getProperty("NOTION_API_KEY"); const DATABASE_ID = PropertiesService.getScriptProperties().getProperty("DATABASE_ID"); const url = 'https://api.notion.com/v1/databases/' + DATABASE_ID + '/query'; function main() { let today = new Date(); let dateThreeMonthsLater = new Date(); dateThreeMonthsLater.setMonth(today.getMonth() + 3); } function getServicesWithinRenewalDate(startDate, endDate) { const payload = { "filter": { "and": [ { "property": "契約期間", "select": { "equals": "年次" } }, { "and": [ { "property": "更新日", "formula": { "date": { "on_or_before": endDate } } }, { "property": "更新日", "formula": { "date": { "on_or_after": startDate } } } ] } ] }, "sorts": [ { "property": "更新日", "direction": "ascending" }, { "property": "名前", "direction": "ascending" } ] }; const options = { 'method': 'POST', 'headers': { 'Notion-Version': '2022-06-28', 'Authorization': 'Bearer ' + NOTION_API_KEY, 'Content-Type': 'application/json' }, 'payload': JSON.stringify(payload), }; let result = JSON.parse(UrlFetchApp.fetch(url, options)); return result; }
通知
取得後は、加工してSlackなどに通知しましょう。 通知を整形したい場合は、Block Kit Builderを使うと便利です。
おわりに
関数酷使は大変ですね。 手段が目的にならないように自制しつつも、notion 芸人するのは楽しいです。
Goodpatchではデザイン好きなエンジニアの仲間を募集しています。 少しでもご興味を持たれた方は、ぜひ一度カジュアルにお話ししましょう!