【初心者向け】GAS+Googleスプレッドシート+LINEBotでやりたいこと逆引き

# はじめに
GAS+GoogleスプレッドシートでLINEBotを作る際に、よくやる処理を逆引きでまとめました

# 前提
CHANNEL_ACCESS_TOKENが定義されている
line_endpointが定義されている
doPostの引数はe
jsonは以下のようにパースされている
```js
const CHANNEL_ACCESS_TOKEN = 'チャネルアクセストークンを貼り付け'; 
const line_endpoint = 'https://api.line.me/v2/bot/message/reply';
function doPost(e) {
  //JSONをパースする
  var json = JSON.parse(e.postData.contents);
}
```

# LINEBot編
詳細を確認したい場合は[公式ドキュメント](https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects)を読んでください

LINEbotから送信されるjsonの中身のサンプルです
```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
      "type": "message",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      },
      "message": {
        "id": "325708",
        "type": "text",
        "text": "@example Hello, world! (love)",
        "emojis": [
          {
            "index": 14,
            "length": 6,
            "productId": "5ac1bfd5040ab15980c9b435",
            "emojiId": "001"
          }
        ],
        "mention": {
          "mentionees": [
            {
              "index": 0,
              "length": 8,
              "userId": "U850014438e..."
            }
          ]
        }
      }
    }
  ]
}
```
こういう構造になっているので以下のように情報を取得できます

## リプライトークン
```js
json.events[0].replyToken;
```

## イベントのタイプ
```js
json.events[0].type
```

## ユーザーID
```js
json.events[0].source.userId
```

## メッセージ
イベントのタイプがmessageだった場合
```js
json.events[0].message.text
```

## postback
イベントのタイプがpostbackだった場合
```js
json.events[0].postback.data
```

## リプライトークンを用いて返信する
```js
var messages = [{'type': 'text', 'text': "テスト返信"}]
UrlFetchApp.fetch(line_endpoint, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': messages,
    }),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
```

# スプレッドシート編
まずこちらで基本的な使い方を覚えましょう
[【GAS初心者】getDataRange関数でのシートの値の取り方6step+1try(GAS)](https://qiita.com/Rihoritsuko/items/d1a26833ead17505e302)

## 使うシートを指定する
```js
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シートの名前');
```

## データ全体を取得
```js
sheet.getDataRange().getValues();
```

[注意点](https://iwb.jp/google-apps-script-spreadsheet-getdatarange/)

## セルのデータを取得
```js
sheet.getRange(行番号,列番号).getValue()
// または英字+数字の文字列
sheet.getRange("A1").getValue()
```

## セルにデータを設定
```js
sheet.getRange(行番号,列番号).setValue("文字列")
// または英字+数字の文字列
sheet.getRange("A1").setValue("文字列")
```

## 列を検索して条件に該当する行番号をすべて取得
```js
function doPost(e) {
  // いろんな処理
  var target_rows = searchData(sheet, 検索する条件, 検索したい行番号)
}

function searchData(sheet, condition, col){
  var allData = sheet.getDataRange().getValues(); // データを全件取得
  var target_rows = []; 
  // ヘッダーを含める場合はi=0で初期値を与える
  for(var i = 1; i < allData.length; i++) { // データを順に調べていく
    // ↓ この部分を変更していろんなパターンが作れる
    // 調べたい列が4列目だとすると、配列は0からはじまるので4-1で3が指定される
    if(allData[i][col-1].indexOf(condition) != -1){　
      target_rows.push(i+1); // 検索に引っかかる箇所の行番号を配列に集める
    }
    // ↑ この部分を変更していろんなパターンが作れる
  }
  return target_rows;
}
```

### 列に指定の文字が一部分でも入っている場合（部分一致）
```js
if(allData[i][col-1].indexOf(condition) != -1){
  target_rows.push(i+1);
}
```

indexOfを利用
[indexOfのドキュメント](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf)

### 列に指定の文字が一部分でも入っている場合(完全一致)
```js
if(allData[i][col-1] == condition){
  target_rows.push(i+1);
}
```

### 列に指定の数以上のものがある場合
```js
if(allData[i][col-1] >= condition){
  target_rows.push(i+1);
}
```

### 列に指定の数以下のものがある場合
```js
if(allData[i][col-1] <= condition){
  target_rows.push(i+1);
}
```

## 配列からランダムにn個取り出したい
```js
function doPost(e){
  // いろんな処理
  var target_rows = searchData(sheet, 検索する条件, 検索したい行番号)
  // target_rowsからランダムにn個取り出したい
  var selected_target_rows = randomSelect(target_rows, 2) // 引数に2を指定したら２つ取得できる
}

function randomSelect(array, n){
  var randomSelect = [];
  while(randomSelect.length < n && array.length > 0){
    const rand = Math.floor(Math.random() * array.length);
    var selected_val = array[rand]
    randomSelect.push(selected_val);
    // ↓ この部分を変更したらいろんなパターンに対応できる　
    array = array.filter(function(v, i) {
      return (v !== selected_val);
    }); // 結果が重複しないように、元の配列からは削除
    // ↑ この部分を変更したらいろんなパターンに対応できる　
  }
  return randomSelect;
}
```

## 該当の要素全部削除
```js
// 以下の配列から3つ取り出すときに[1,1,x]はナシにしたい
[1,2,3,4,5,1]

array = array.filter(function(v, i) {
      return (v !== selected_val);
    });
```

## 該当の要素だけ削除
```js
// 以下の配列から3つ取り出すときに[1,1,x]はアリだけど、[2,2,x]はナシ
[1,2,3,4,5,1]

array[rand]　= "" //取り出しところを特定の文字で埋める
array = array.filter(function(v, i) {
      return (v !== ""); // その文字を除外
    });
```

## 重複を許す
```js
// 以下の配列から3つ取り出すときに[1,1,x]でも、[2,2,2]でもあり
[1,2,3,4,5,1]

// 何も書かない
//array = array.filter(function(v, i) {
//      return (v !== selected_val);
//    });
```

# おわりに
かなり限定的だと思うので、都度追加していきます。
コメントもお待ちしてます🙇‍♂️