Airtable でデータを記録して前のコメントを返事するシンプルな LINE BOT をつくったメモ
Airtable でデータを記録して前のコメントを返事するシンプルな LINE BOT をつくったメモです。
LINE BOT の基礎
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest - Qiita
こちらを参考に LINE BOT の基礎 ができている前提で進めます。
2022 年 7 月の情報で進めます。
Airtable の API Key を控えておく

Airtable のアカウントページ で API Key をテキストエディタにメモしておきます。これはこの後の Node.js のソースコードで使います。
今回用の Airtable の Base を作成

Airtable のダッシュボードで今回用の Base を作成します。

今回は名前を LINE BOT Sample としました。
今回用の Airtable の Table を作成

Table を一つ作成します。名前は Record とします。

フィールドの名前とフィールドタイプは以下のようにします。
- UserID
- フィールドタイプ
- Single line text
- フィールドタイプ
- Message
- フィールドタイプ
- Long text
- フィールドタイプ
- CreatedAt
- フィールドタイプ
- Created time
- フィールドタイプ
これで準備完了です。
今回用の Airtable の Base の ID を取得
今回用の Airtable の Base の ID を取得します。

Airtable の API ページ から今回の Base をクリックします。

今回の Base の API ページに移動すると、こちらで app ではじまる Base ID が取得できるのでテキストエディタにメモしておきます。
プロジェクトフォルダで Node.js のパッケージ準備
Visual Studio Code で今回作業するプロジェクトフォルダを開きます。
npm init -y
プロジェクトフォルダ直下で npm の初期化をします。
npm i @line/bot-sdk express
LINE BOT 関連のパッケージのインストールをします。
npm i airtable
Airtable のパッケージのインストールをします。
Node.js のプログラム準備
プロジェクトフォルダ直下に app.js のファイルを作成して以下のプログラムをコピーペーストします。
'use strict';
// Airtable /////////////////////////////////
const Airtable = require("airtable");
// 今回使う Base の Base ID
const BASE_ID = 'BASE_ID';
// Airtable の API Key
const AIRTABLE_API_KEY = 'AIRTABLE_API_KEY';
// Airtable 今回使うの Base を取得
const base = new Airtable({apiKey: AIRTABLE_API_KEY}).base(BASE_ID);
// 今回使う Table を取得(テーブル名:Record)
const table = base('Record');
// LINE /////////////////////////////////////
const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
const config = {
channelSecret: 'channelSecret',
channelAccessToken: 'channelAccessToken'
};
const app = express();
app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});
const client = new line.Client(config);
async function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// Airtable から一つ前の投稿を取得
let records;
try {
records = await base('Record').select({
view: 'Grid view',
maxRecords: 1,
sort:[
{
field: "CreatedAt",
direction: "desc"
}
],
fields: ["UserID", "Message","CreatedAt"]
}).all();
} catch (e){
console.log(e);
}
let message = '';
if(records.length == 0){
// まだ一つ前の投稿がないとき(はじめての投稿)
message = `今回のメッセージは\n「${event.message.text}」\nです。はじめての投稿です。`;
} else {
const previousMessage = records[0].get('Message');
message = `今回のメッセージは\n「${event.message.text}」\nです。\n一つ前の投稿は\n「${previousMessage}」\nです。`;
}
// Airtable に今回のメッセージを記録
await table.create([{
"fields": {
"UserID": event.source.userId,
"Message": event.message.text
}
}]);
return client.replyMessage(event.replyToken, {
type: 'text',
text: message
});
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);
コピーアンドペーストできたら、設定をします。
// 今回使う Base の Base ID
const BASE_ID = 'BASE_ID';
// Airtable の API Key
const AIRTABLE_API_KEY = 'AIRTABLE_API_KEY';
今回使う Base の Base ID と Airtable の API Key を反映します。
const config = {
channelSecret: 'channelSecret',
channelAccessToken: 'channelAccessToken'
};
今回使う LINE の channelSecret と channelAccessToken を反映します。
設定できたら LINE BOT を動かしてみます。
動かしてみる
Airtable の Base が空の状態で「やほー」とメッセージしたあと、「こんにちは!」とメッセージします。

Base にはこのように情報が貯まります。

そして、このようにやりとりされます。「やほー」を送ったときは、はじめての投稿なので今回のメッセージのみで前のメッセージはなし、それ以降は、今回のメッセージと一つ前のメッセージを返答します。
Airtable から一つ前の投稿を取得する処理
一つ前の投稿を取得する、大事な部分はここです。
// Airtable に今回のメッセージを記録
await table.create([{
"fields": {
"UserID": event.source.userId,
"Message": event.message.text
}
}]);
まず、Airtable にデータが登録されるときに CreatedAt で自動的に作成日時が登録されます。UserID と Message しか登録していないんのですが、CreatedAt で自動的に作成日時が登録されます。

そして、データの取得です。
// Airtable から一つ前の投稿を取得
let records;
try {
records = await base('Record').select({
view: 'Grid view',
maxRecords: 1,
sort:[
{
field: "CreatedAt",
direction: "desc"
}
],
fields: ["UserID", "Message","CreatedAt"]
}).all();
} catch (e){
console.log(e);
}
こちらのコードで sort パラメータで CreatedAt を狙ってソートをかけます。その上で maxRecords 1 によって 1 件だけ取得することで最新のデータ取得を実現しています。