4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

kintoneコマンドラインツールでUPSERTしてみた

Last updated at Posted at 2016-05-10

前回の「kintoneコマンドラインツールでデータ登録してみた」では、kintoneの異なるアプリのデータを定期的に別のアプリにコピーする方法を紹介しました。今回はコピー(追加)ではなく、UPSERT(キーとなる値があったら更新、なかったら追加)する方法を紹介したいと思います。

イメージ

20160505-1-37_No-00.png

kintoneにはUPSERTするAPIがないのですが、2016年5月にアップデートされた kintone API(レコード番号以外のキー項目でレコードの更新)を利用して次のようにINSERTとUPDATEを使い分けることにしました。

INSERT
アプリB(コピー先)の最大KeyCode(アプリAのレコードID)より大きいレコードIDを持ったアプリAのデータを抽出してアプリBに登録する。
※アプリAからアプリBにコピーする想定で、他のツールや人の操作によるレコード追加は想定していません。

UPDATE
アプリB(コピー先)のキー日時(レコードごとの処理した日時)の最大が、アプリAの更新日時以下のレコードIDを持ったアプリAのデータを抽出してアプリBに更新する。
※INSERTの後にUPDATEするため、INSERTするデータがUPDATEするデータにも含まれますが、kintone APIでは変更のないデータは更新しない仕様です。

kintoneコマンドラインツールを用意する

kintoneコマンドラインツール」を使います。このツールを使った過去の記事を紹介します。

2つのアプリを用意する

異なるドメインでkintoneアプリをそれぞれ 1つずつ用意します。
※同じドメイン内の異なるアプリ間でも動作します。
kintoneの環境を持っていない!という方、cybozu.com developer networkで無償の開発者ライセンスを取得しておきましょう。

アプリの構成

アプリA

| フィールドコード | フィールドタイプ |
|:-----------|:------------|
| TitleA | 文字列(1行)|
| NumberA | 数値 |
| UpdateDatetime | 更新日時(組み込み)|

アプリB

| フィールドコード | フィールドタイプ | 備考 |
|:-----------------|:------------|:------------|
| KeyCode | 数値 | 重複なし(コピー元のレコードIDを保存) |
| KeyUpdateDatetime| 日時 | 処理した日時を保存 |
| TitleB | 文字列(1行)| |
| NumberB | 数値 | |

レコード登録画面

(フィールド名とフィールドコードを同じにしています)
アプリA

img_20160203095822.png

アプリB

20160505-23-19_No-01.png

kintoneコマンドラインツールに必要な情報

アプリA

| パラメータ | 値 |ここで実験する値 |
|:----------|:----------------|:------------|
| -a | アプリID |85 ※IDはURLに表示されています。 |
| -d | サブドメイン名 |sample1.cybozu.com ※サブドメイン名は各自異なります。
| -t | APIトークン |De5Xb3TM1TDccdqEM20eP1dpesjuBLckOx6AyM4n ※アプリの管理画面から発行できます。|

アプリB

| パラメータ | 値 |ここで実験する値 |
|:----------|:----------------|:------------|
| -a | アプリID |822 ※IDはURLに表示されています。 |
| -d | サブドメイン名 |sample2.cybozu.com ※サブドメイン名は各自異なります。
| -t | APIトークン |BoNFRmX0oDoKQMSrTiZC7hbEmb9QaZa1vYVfnyD4 ※アプリの管理画面から発行できます。|

それぞれの値は環境によって異なります。

いよいよ本題!シェルスクリプトを実行してみよう

Linux環境の場合、次のシェルスクリプトをUTF-8で保存しましょう。
ここでのファイル名は「upsert.sh」にしておきます。

次の処理をシェルスクリプトで実現してみます。

  1. アプリB(コピー先)から最大KeyCode(アプリAのレコードID)を取得する
  2. 最大KeyCodeより大きいレコードIDを持ったアプリAのデータを抽出してアプリBに登録する
  3. アプリB(コピー先)のキー日時(レコードごとの処理した日時)の最大を取得する
  4. その最大キー日時がアプリAの更新日時以下のレコードIDを持ったアプリAのデータを抽出してアプリBに更新する

説明

--- self setting ---で囲まれた部分のみ変更しましょう。

  • ### APP_A内の変数にアプリAの情報を設定
  • ### APP_B内の変数にアプリBの情報を設定
  • ### Mapping custom 内の変数にコピー元のフィールド:コピー先のフィールドを設定
    • TitleAからTitleBにコピーする際には、TitleA:TitleB と書きます
    • $idなど「$」を使う際にはエスケープしましょう
    • コピーするフィールドに応じて増やしましょう

プログラム

upsert.sh
#!/bin/bash

# --------------- self setting ------------------
### character encoding
OUTPUT_TYPE="sjis"
#OUTPUT_TYPE="utf-8"

### APP_A
APP_ID_A="85"
SUB_DOMAIN_A="sample1"
API_TOKEN_A="De5Xb3TM1TDccdqEM20eP1dpesjuBLckOx6AyM4n"
KEY_DATETIME_A="UpdateDatetime"

### APP_B
APP_ID_B="822"
SUB_DOMAIN_B="sample2"
API_TOKEN_B="BoNFRmX0oDoKQMSrTiZC7hbEmb9QaZa1vYVfnyD4"
UNIQUE_B="KeyCode"
KEY_DATETIME_B="KeyUpdateDatetime"
QUERY_B_INSERT="$UNIQUE_B != \"\" order by $UNIQUE_B desc limit 1"
QUERY_B_UPDATE="$UNIQUE_B != \"\" order by $KEY_DATETIME_B desc limit 1"

# Mapping
declare -a ARR_MAPPING=()
# Mapping define
ARR_MAPPING+=("\$id:KeyCode")
ARR_MAPPING+=("UpdateDatetime:KeyUpdateDatetime")
### Mapping custom
ARR_MAPPING+=("TitleA:TitleB") #sample:\$id,Title,Number,...
ARR_MAPPING+=("NumberA:NumberB")
# --------------- self setting ------------------

# Set cli-kintone files
CLI_FILES="cli-kintone"
BASE_DIR=$(cd $(dirname $0); pwd)
if [ ! -f "$BASE_DIR/$CLI_FILES" ]; then
    echo "Not found $CLI_FILES files."
    exit 1
fi
# Create files dirctory
OUTPUT_DIR="files"
BASE_DIR=$(cd $(dirname $0); pwd)
if [ ! -e "$BASE_DIR/$OUTPUT_DIR" ]; then
    mkdir -p "$BASE_DIR/$OUTPUT_DIR"
fi

# Set header fields
declare -a ARR_FIELDS_A=()
declare -a ARR_FIELDS_B=()
for i in "${ARR_MAPPING[@]}"
do
   ARR_FIELDS_A+=(`echo $i | cut -d":" -f1 | cut -d":" -f1`)
   strB=\"`echo $i | cut -d":" -f2 | cut -d":" -f1`\"
   ARR_FIELDS_B+=($strB)
done
OUTPUT_FIELDS="$(IFS=,; echo "${ARR_FIELDS_A[*]}")"
INSERT_FIELDS="$(IFS=,; echo "${ARR_FIELDS_B[*]}")"
UPDATE_FIELDS="$(IFS=,; echo "${ARR_FIELDS_B[*]}")"
# Set update field flg
UPDATE_FIELDS=`echo $UPDATE_FIELDS | sed -e "s/\"$UNIQUE_B\"/\"*$UNIQUE_B\"/"`

# Set datetime file
DATETIME=`date +%Y%m%d%H%M%S.%2N`
OUTPUT_FILE="output$DATETIME.csv"
OUTPUT_PATH=$BASE_DIR/$OUTPUT_FILE

# ---Get Update datetime Script----------------------
# Get max data
MAX_LIST=(`./$CLI_FILES -a $APP_ID_B -d $SUB_DOMAIN_B -t $API_TOKEN_B -e $OUTPUT_TYPE -c "$KEY_DATETIME_B" -q "$QUERY_B_UPDATE"`)
MAX_DATA=$(echo ${MAX_LIST[1]} | sed s/\"//g)
if [ -n "$MAX_DATA" ] ; then
    QUERY_A_DATE="$KEY_DATETIME_A > ${MAX_LIST[1]}"
fi
echo $QUERY_A_DATE

# ---Insert Script------------------------------------
# Get max data
MAX_LIST=(`./$CLI_FILES -a $APP_ID_B -d $SUB_DOMAIN_B -t $API_TOKEN_B -e $OUTPUT_TYPE -c "$UNIQUE_B" -q "$QUERY_B_INSERT"`)
MAX_DATA=${MAX_LIST[1]}
if [ -z "$MAX_DATA" ] ; then
    MAX_DATA="0"
    echo "Changed ID."
fi
MAX_DATA=`echo $MAX_DATA | sed s/\"//g`
QUERY_A="\$id > $MAX_DATA"
echo $QUERY_A

# Excute output file
./$CLI_FILES -a $APP_ID_A -d $SUB_DOMAIN_A -t $API_TOKEN_A -e $OUTPUT_TYPE -c "$OUTPUT_FIELDS" -q "$QUERY_A" >> $OUTPUT_FILE

# Change csv header
INSERT_FILE="Insert$DATETIME.csv"
find . -name "$OUTPUT_FILE" | sed -i -e "1,1d" $OUTPUT_FILE
find . -name "$OUTPUT_FILE" | sed -i -e "1i $INSERT_FIELDS" $OUTPUT_FILE
find . -name "$OUTPUT_FILE" | mv "$OUTPUT_FILE" "$INSERT_FILE"
echo "Insert file: $INSERT_FILE"

# Excute import file
./$CLI_FILES -a $APP_ID_B -d $SUB_DOMAIN_B -t $API_TOKEN_B -e $OUTPUT_TYPE -f "$INSERT_FILE"
mv "$INSERT_FILE" "$OUTPUT_DIR"
echo "Finished insert data."

# ---Update Script------------------------------------
# Excute output file
./$CLI_FILES -a $APP_ID_A -d $SUB_DOMAIN_A -t $API_TOKEN_A -e $OUTPUT_TYPE -c "$OUTPUT_FIELDS" -q "$QUERY_A_DATE" >> $OUTPUT_FILE

# Change csv header
UPDATE_FILE="Update$DATETIME.csv"
find . -name "$OUTPUT_FILE" | sed -i -e "1,1d" $OUTPUT_FILE
find . -name "$OUTPUT_FILE" | sed -i -e "1i $UPDATE_FIELDS" $OUTPUT_FILE
find . -name "$OUTPUT_FILE" | mv "$OUTPUT_FILE" "$UPDATE_FILE"
echo "Update file: $UPDATE_FILE"

# Excute import file
./$CLI_FILES -a $APP_ID_B -d $SUB_DOMAIN_B -t $API_TOKEN_B -e $OUTPUT_TYPE -f "$UPDATE_FILE"
mv "$UPDATE_FILE" "$OUTPUT_DIR"
echo "Finished update data."

シェルスクリプトを実行してみる

$ ./upsert.sh

できた!!
処理したファイルは、filesフォルダにそれぞれ Insert~.csv、Update~.csv というファイルで、保存しています。
20160505-23-12_No-00.png

さいごに

いかがでしたでしょうか。kintoneコマンドラインツールとシェルスクリプトを使うと 定期的に、別会社(ドメイン)へデータを同期して活用 することができますね。お試しください。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?