Kintoneを運用されている企業や個人の場合、Googleスプレッドシートで管理していたり、別システムからGoogleスプレッドシートにインポートしているデータを、Kintoneアプリに同期したいシーンが割りかし多い印象です。

そのようなご依頼を頂戴する場合は、下記のようなGAS(Google Apps Script)を使用してスプレッドシート ⇒ Kintoneへ自動同期させています。

Web上に同様なコードはたくさん転がっていますが、私が作成したサンプルコードの主な仕様は以下の通りです。

<利点>

・キーフィールドを指定して、Kintoneアプリ内にそのキーを持つレコードが存在しない場合は新規登録、存在する場合はレコードを更新
・KIntoneに同期したいデータをシート上の見出し列で指定可能

<サンプルコードの仕様>

・スプレッドシートの対象シートの「メールアドレス」「氏名」「購入日」「売上」の見出し列を指定
・「メールアドレス」が空の行はスキップ(同期対象外)
・「氏名」が空の場合は、"氏名不明" で登録 or 更新
・「メールアドレス」と「購入日」が同一のレコードの存在有無を新規登録 or 更新のキーとして設定

サンプルコードをカスタマイズすればかなり便利にご利用いただけるかと思いますので、ぜひ、ご自由にお使いください!

※ご質問にはお答えできませんので予めご承知おきくださいませ。

スプレッドシートイメージ

コード

const sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート名");

const kDomain = "kintoneのドメイン";
const kUrl = `https://${kDomain}.cybozu.com/k/v1/record.json`;
const kUrls = `https://${kDomain}.cybozu.com/k/v1/records.json`;

const apiToken = "対象アプリのAPIトークン";
const appId = "対象アプリのID";

function exportToKintone() {
  // kintoneアプリに登録or更新したいシート列を見出し名で指定
  const headersToCopy = [
    "メールアドレス",
    "氏名",
    "購入日",
    "売上",
  ];

  const sourceData = sourceSheet.getDataRange().getValues();
  const sourceHeaders = sourceData[0];
  const sourceHeaderIndexesToCopy = [];

  // 対象列の見出し名インデックスを取得
  for (let i = 0; i < headersToCopy.length; i++) {
    const index = sourceHeaders.indexOf(headersToCopy[i]);
    if (index !== -1) {
      sourceHeaderIndexesToCopy.push(index);
    }
  }

  for (let row = 1; row < sourceData.length; row++) {
    let postRecord = {};
    let date = null;
    let mail = null;

    for (const colIndex of sourceHeaderIndexesToCopy) {
      let val = sourceData[row][colIndex];

      if (sourceHeaders[colIndex] === "氏名") {
        if (val) {
          postRecord["氏名"] = { value: val };
        } else {
          postRecord["氏名"] = { value: "氏名不明" };
        }
        continue;
      }

      if (sourceHeaders[colIndex] === "購入日") {
        if (val) {
          postRecord["購入日"] = { value: Utilities.formatDate(val, "JST", "yyyy-MM-dd") };
          date = Utilities.formatDate(val, "JST", "yyyy-MM-dd");
        }
        continue;
      }

      if (sourceHeaders[colIndex] === "メールアドレス") {
        if (val) {
          postRecord["メールアドレス"] = { value: val };
          mail = val;
        }
        continue;
      }

      if (sourceHeaders[colIndex] === "売上") {
        if (val) {
          postRecord["売上"] = { value: val };
        }
        continue;
      }
    }

    if (!mail) {
      continue;
    }

    // メールアドレス×購入日が同一のレコードが存在するかを確認
    let existingRecord = searchKintoneRecord(
      mail,
      date,
      apiToken,
      appId
    );

    if (existingRecord) {
      // レコードが既に存在する場合は情報を更新
      updateKintoneRecord(
        postRecord,
        apiToken,
        appId,
        existingRecord.$id.value
      );
    } else {
      // レコードが存在しない場合は新規登録
      createKintoneRecord(postRecord, apiToken, appId);
    }
  }
}

function searchKintoneRecord(
  mail,
  date,
  apiToken,
  appId
) {
  const query = `メールアドレス = "${mail}" and 購入日 = "${date}"`;

  const options = {
    method: "get",
    headers: {
      "X-Cybozu-API-Token": apiToken,
    },
  };
  const res = UrlFetchApp.fetch(
    `${kUrls}?app=${appId}&query=${encodeURIComponent(query)}`,
    options
  );
  const json = res.getContentText();
  const data = JSON.parse(json);

  if (data.records.length > 0) {
    return data.records[0];
  } else {
    return null;
  }
}
function createKintoneRecord(record, apiToken, appId) {
  let sendData = {
    app: appId,
    record: record,
  };

  const options = {
    method: "post",
    contentType: "application/json",
    headers: {
      "X-Cybozu-API-Token": apiToken,
    },
    payload: JSON.stringify(sendData),
  };
  const res = UrlFetchApp.fetch(kUrl, options);
  console.log(JSON.stringify(sendData));
  return res;
}

function updateKintoneRecord(record, apiToken, appId, recordId) {
  let sendData = {
    app: appId,
    id: recordId,
    record: record,
  };

  const options = {
    method: "put",
    contentType: "application/json",
    headers: {
      "X-Cybozu-API-Token": apiToken,
    },
    payload: JSON.stringify(sendData),
  };
  console.log(JSON.stringify(sendData));
  const res = UrlFetchApp.fetch(kUrl, options);
  return res;
}

トリガー設定

トリガーは「時間手動型」から「時間ベース」や「日付ベース」で定期実行されるように設定してください。