非技術者PdMが、Slackワークフロー投稿をNotionデータベースへ溜めるGAS書いてみたよ

# はじめに
この記事はHRBrain Advent Calendar 2022カレンダー1の25日目の記事です。

https://qiita.com/advent-calendar/2022/hrbrain

こんにちは。株式会社HRBrainでプロダクトマネージャー（以下PdM）をしている田中です。


去年はPdMとして新米すぎて[武道館に立ったことを記事](https://times.hrbrain.co.jp/entry/2021/12/15/rookie-PdM-try)にしてしまいました。

今年も相変わらずPdMとは何かがわかっていませんが、自分が欲しかったものを技術でカタチにできたので、それを記事としてアウトプットしてみたいと思います。
アドベントカレンダーのトリであることは何も気にしていません。

本記事では、非技術者である私が、Slackのワークフロー投稿をNotionのデータベースへ自動蓄積させることができた方法を紹介します。

# そもそもなんで作ろうと思ったか
プロダクト開発において、特にPdMに当たる方は以下のようなことを思うシーンがあるのではないでしょうか。
* ナレッジやフィードバック、要望を蓄積し、定量化したり共有化して組織の資産としたい
* その投稿や蓄積はできる限り負担なく運用したい

価値の単位を小さく区切り、スピード感を持ってお客様にプロダクトを届けることを重視する弊社の開発において、実際に上記のようなことを思うシーンが多々あり、私自身非常に困ってました。

「ナレッジや要望をSlackで気軽に投稿しやすくしつつ、その内容が全社のドキュメントツールであるNotionに自動で溜まってみんなで見返せるような仕組みがほしいなあ」といったあるあるな要望を考えると同時に、「PdMになって1年経ったし、自分で作ってみるか」と自ら解決するモチベーションも湧いてきました。

そうして私が抱える課題を技術で解決する挑戦の旅が始まりました。

# 方法の紹介の前に
今回、私の夢を実現するにあたり、主に以下の記事を参考にさせていただきました。

https://tech.crassone.jp/posts/stock-information-from-slack-to-notion

非常に有益な情報を公開いただいていた先人の方がいらっしゃり大変感謝したと同時に、こうした情報を積極的に公開する技術の業界は素晴らしいなと再確認しました。


# こうして私の夢は叶いました
### 仕組み
今回以下を駆使してSlackワークフローとNotionのデータベースを連携させました。
* Notion（NotionAPI）
* Slackワークフロー
* Google スプレッドシート（以下、スプレッドシート）
* Google Apps Script（以下GAS）

![説明用画像9_20221225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/ed862fcd-56b3-c889-b819-68ecd1b00a03.png)



非技術者の私にとってGASやNotionAPIに触れることは、[竜神大吊橋バンジージャンプ](https://www.ibarakiguide.jp/seasons/recommend/ryujin-bungy.html)を飛ぶときよりも勇気が必要でしたが、実現させたい気持ちが背中を押してくれました。

夢って大事ですね。

### やりたかったこと
Slackのワークフローで投稿されたものが、Notionのデータベースに自動で蓄積されていくこと。
詳細は以下に説明しますが、スプレッドシートの最後の行のデータのみがNotionのデータベースに送信されるようなGASを書いたことが、今回の私なりの工夫です。


すごく褒めて欲しい。


### 手順
この説明を書いてる人間が非技術者のため、技術者の方から見たら品質が低いかもしれません。少し目を瞑っていただけると幸いです。

#### 0. 以下を準備する
* 使用したいSlackのワークフロー
* ワークフローで投稿されたものを溜めるためのスプレッドシート。なんでもいいです。
* 溜めていきたいNotionのデータベースのID
    * データベースのURLの`notion.so/`と`?v=`間の◯の部分です
    *  `https://www.notion.so/〇〇〇〇〇〇?v=xxxxxxxxxxx`
* NotionのIntegration Token
    * [公式ドキュメント](https://www.notion.so/ja-jp/help/create-integrations-with-the-notion-api)を参照
    * ちなみに権限を持っていないとIntegration Tokenを発行できないみたいです。私は社内のシステム管理者に発行してもらいました
* GAS
    * 詳細は後述


#### 1.ワークフローで更新したいNotionのページにIntegrationを追加する


![説明用画像8_20221225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/722be670-bc7a-9bbf-ea3c-729fdfff72c9.png)


※閲覧するタイミング次第でNotionのアップデートにより画面が変わっている可能性もあります


#### 2. Slackのワークフローを溜めていく任意のスプレッドシートに、連携する項目のNotion DBのヘッダー名と同じ見出しをつけておく

![説明用画像2_20221225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/3d252b97-98f2-3150-d2d6-b7c626a67ef1.png)


#### 3. Slackワークフローを作成し、スプレッドシートに蓄積するStepを設定する
* Slackワークフローの作成方法：[公式ドキュメント](https://slack.com/intl/ja-jp/help/articles/360053571454-Slack-%E3%81%A7%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)
* スプレッドシートへの連携及びStepの設定方法：[公式ドキュメント](https://slack.com/intl/ja-jp/help/articles/11086384874259-%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%83%93%E3%83%AB%E3%83%80%E3%83%BC%E3%81%A7-Google-%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)

![説明用画像3_20221225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/856e6f17-707c-abe6-54a4-a136bd5ad412.png)

①スプレッドシートのカラムを選択し、
②スプレッドシートの送信したい変数を選択する
だけなので結構カンタンにできます。

#### 4. 連携先のスプレッドシートでGASを組む

ついに、私の冒険が始まります。

#####  4-1. GASを開く

![説明用画像4_20221225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/3eae40df-1a23-8f6c-8d7a-62cbee3040ec.png)



##### 4-2. GASを書く


```jsx
// NotionのIntegration Tokenを""内に入力
const NOTION_TOKEN = "〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇";
// NotionのDatabaseIDを""内に入力。DatabaseのURLの「〜〜so/〇〇◯◯?v=〜〜」の〇〇のところ
const DATABASE_ID = "〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇";

function myFunction() {
  // スプレッドシートからアクティブのシートを取得する
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  // すべてのセル範囲とすべてのセルの値を取得
  const js = convertJson(ss.getDataRange().getValues());
  // 取得したセルの情報のうち最後の要素だけ取得
  const ld = js.slice(-1);
  
  ld.forEach(function (elem, index) {
  // スプレッドシートの内容のJSON配列から、Notionのデータベースにマッピング
    const obj = {
      "parent": {
        "database_id": DATABASE_ID
      },
   // スプレッドシートのヘッダー名とNotion DBのヘッダー名を入れていく
      "properties": {
        "タイトル": {
          "title": [
            {
              "text": {
                "content": elem.タイトル
              }
            }
          ]
        },
        "詳細": {
          "rich_text": [
            {
              "text": {
                "content": elem.詳細
              }
            }
          ]
        },
       "カテゴリ": {
          "select":{
            "name":"質問",
            "name":"不具合・バグ",
            "name":"フィードバック",
          }
        },
        "記載者": {
          "rich_text": [
            {
              "text": {
                "content": elem.記載者
            }
          }
        ]
      }
    }  
  };
   postNotion(obj);
   Utilities.sleep(1000);
  });
}

// Notionに対してアイテムを登録
function postNotion(object){
  const options = {
  method: 'post',
  headers: {
    'Content-Type': 'application/json',
    'Notion-Version':'2022-06-28',
    'Authorization':"Bearer "+NOTION_TOKEN
  },
  payload: JSON.stringify(object)
};
console.log(options)
  var response = UrlFetchApp.fetch('https://api.notion.com/v1/pages', options);

}

// スプレッドシートの内容の配列からJSON配列に加工する
function convertJson(range) {
  const key = range[0];

  const js = range.slice(1).map(
    function (row) {
      const obj = {};
      row.map(function (item, index) {
        obj[String(key[index])] = item;
      }
      );
      return obj;
    });
  return js;
}
```

NotionのデータベースのPropertyに関する情報は[公式ドキュメント](https://developers.notion.com/reference/property-object#number-configuration)を参照


##### 4-3. トリガーをスプレッドシート変更時に設定する
![説明用画像5_20221225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/8f34f12f-c2fc-40a8-15dc-8205cb5e67cc.png)

Slackワークフローが投稿されたとき＝スプレッドシートにデータが追加されたときに、このスクリプトが起動しNotionへデータが送信されるように、イベントの種類を「変更時」に設定しておきましょう。
![説明用画像6_20221225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/b462381b-86b8-60e2-3d31-fa3bd4b3373d.png)




#### ついに完成🎉

これでSlackワークフローが投稿されるとNotionのデータベースへ自動蓄積されるようになりました。
![notion連携for qiita.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294641/7c46cce5-ae8f-c9eb-a5da-dc714299e503.gif)




## ついに夢叶う。そして次の夢へ。
週末も血眼でGASとにらめっこしていたこともあり、こうして私の夢は叶いました。

しっかりと業務にも活かすことができており、ともに開発を進める弊社テックリードの鈴木（善）の[未完成の価値に着目して不確実性の高い開発に向き合った話](
https://qiita.com/4486/items/6eae2840160d4f06cc84#:~:text=%E5%85%B7%E4%BD%93%E7%9A%84%E3%81%AB%E3%81%AF%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%89%E3%81%8B%E3%82%89%E7%B4%8460%E4%BB%B6%E3%81%AE%E3%83%95%E3%82%A3%E3%83%BC%E3%83%89%E3%83%90%E3%83%83%E3%82%AF%E3%82%92%E5%BE%97%E3%82%89%E3%82%8C%E3%80%81%E3%81%9D%E3%81%AE%E3%81%86%E3%81%A116%E4%BB%B6%E3%81%AF%E3%81%99%E3%81%A7%E3%81%AB%E4%BF%AE%E6%AD%A3%E3%82%84%E6%94%B9%E5%96%84%E3%81%A8%E3%81%97%E3%81%A6%E3%83%97%E3%83%AD%E3%83%80%E3%82%AF%E3%83%88%E3%81%AB%E5%8F%8D%E6%98%A0%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)の記事内でも取り上げられていますが、
未完成のプロダクトに対するフィードバックを現在では80件近い数まで収集することができており、開発サイド・ビジネスサイドという垣根を越えて全社でプロダクト開発を進めるという挑戦ができているのではないかと実感しています。

また他チームでも私と同様の課題感を持っていたメンバーも多く、この連携手段を採用するチームもありました。

横展開できるようにちゃんとドキュメント作ってよかった。
記事中2回目ですが、すごく褒めて欲しい。


過去の私の夢は叶ったわけですが、私の技術力は本職のエンジニアの1%にも満たないことを実感しました。
今後は、そんなエンジニアの技術力を確かに世の中に届け、HRBrainに期待してくれたユーザーの方々を幸せにしづつけることを大きな夢として、実現しづつけられる努力をしていきたいと思います。

## 最後に
今回、自分にとって技術を業務に活かす初めての成功体験を得られたわけですが、非技術者バックグラウンドとなる私にとって、今まで体感し難かったエンジニアリングのリアルを肌で感じられたことがより有意義だったのではないかと思っています。
* たったひとつの誤入力でコードは動かなくなる。それを見つけるのにめちゃ時間かかって発狂しそうになる。
* シンプルなロジックを思いつけばカンタンに解決方法がひらめく。そのロジックを考えるのに頭を悩まし、時間を費やす
* 誰でも使用できるようにコーディングしたりドキュメント残すの辛い。でも組織だからそれが重要。

などなど

 

エンジニアなら普通の感覚かもしれませんが、その普通を知ることができたことが私にとっては大きな価値で、さらにエンジニアに対するリスペクトが増しました。
今回気軽に相談に乗ってくれた弊社フロントエンドエンジニア村崎にも感謝です。
（そんな村崎によるアドベントカレンダーの記事は[こちら](https://qiita.com/purpleeeee/items/1d8c4264be2b35a428b1)）


そんな私が働くHRBrainでは、ともに開発する仲間を積極採用中です。
まずはカジュアルにお話だけでもしてみませんか。


https://www.hrbrain.co.jp