kintone マイグレーション（レコード追加）

kintoneアプリを別ドメインに移行する際に必要なデータマイグレーション処理を、cli-kintoneを使って行う手順です。

# 移行シナリオ

* 顧客台帳などのマスタ系アプリのレコードを別ドメインに移行したい場合
* 本環境のレコードをバックアップ環境にコピーする場合

## 注意点

* ソート順を考慮します。（クエリを指定してソート）
* $id、作成日付、関連レコードなど更新できないフィールドを考慮します（更新できないフィールドを除くなどの処理）

# 処理概要

下記の流れで処理を行います。
今回レコードを読み込む前処理にRubyを使っていますが、他のプログラミング言語を利用する場合でも考え方は同じですので、適宜読み替えて下さい。

1. cli-kintoneにてレコード取得
2. 前処理
3. cli-kintoneにてデータ追加

# 全体コード

```insert_record.rb
require 'rubygems'
require 'bundler/setup'
require 'dotenv/load'
require 'open3'
require 'csv'
require 'stringio'
require 'pp'

SUBDOMAIN = ENV['SUBDOMAIN']
APP_FROM = ENV['APP_FROM']
API_FROM = ENV['API_FROM']
APP_TO = ENV['APP_TO']
API_TO = ENV['API_TO']
SELECT_COLUMN = ENV['SELECT_COLUMN']

# INSERT
def do_insert(domain, app_from, app_to, api_from, api_to, select_column)
  from_str = %Q(cli-kintone -d #{domain} -a #{app_from} -c '\"$id,#{select_column}\"' -t #{api_from})
  out, err, status = Open3.capture3(from_str)
  puts "Output = #{out}"
  puts "Error = #{err}"
  puts "Status = #{status}"

  lines = []
  out.each_line { |line| lines << (line.chomp).parse_csv }
  line_header = [*(lines[0])[1..-1]]
  line_body = (lines[1..-1].sort { |a, b| a[0].to_i <=> b[0].to_i}).map { |row| row[1..-1] }
  input_lines = [line_header, *line_body]
  csv_out =  StringIO.new
  input_lines.each { |a| csv_out << a.to_csv }
  File.open('debug.csv', 'w') { |f| f << csv_out.string }
  to_str = %Q(cli-kintone --import -d #{domain} -a #{app_to} -t #{api_to})
  out2, err2, status2 = Open3.capture3(to_str, :stdin_data => csv_out.string)
  puts "Output = #{out2}"
  puts "Error = #{err2}"
  puts "Status = #{status2}"
end

do_insert(SUBDOMAIN, APP_FROM, APP_TO, API_FROM, API_TO, SELECT_COLUMN)
```

# 処理説明

主な処理を説明します。

## 1. cli-kintoneにてレコード取得

cli-kintoneでフィールドを指定してレコードを取得します。

クエリでソート順を指定しても良いです。

```ruby
  from_str = %Q(cli-kintone -d #{domain} -a #{app_from} -c '\"$id,#{select_column}\"' -t #{api_from})
```

[Open3.capture3](https://docs.ruby-lang.org/ja/latest/class/Open3.html#M_CAPTURE3)はRubyから外部プログラムを実行する仕組みです。Perl,Pythonなど他のプログラミング言語の場合は適宜読み替えて下さい。

## 2. 前処理

今回は前処理にてレコードID(\$id)の昇順でソートをしています。

* 3行目でヘッダー行から\$id列を除いています。
* 4行目で\$idの昇順でソートし、さらにデータ行から\$id列を除いています。
* 7行目でバッファーにCSV形式で書き出しています。

```ruby
1  lines = []
2  out.each_line { |line| lines << (line.chomp).parse_csv }
3  line_header = [*(lines[0])[1..-1]]
4  line_body = (lines[1..-1].sort { |a, b| a[0].to_i <=> b[0].to_i}).map { |row| row[1..-1] }
5  input_lines = [line_header, *line_body]
6  csv_out =  StringIO.new
7  input_lines.each { |a| csv_out << a.to_csv }
```

## 3. cli-kintoneにてデータ追加

レコードを読み込みます。
$idを除いているので、レコードは新規に追加されます。
標準出力から読み込む為に、--import オプションを渡しています。

```ruby
  to_str = %Q(cli-kintone --import -d #{domain} -a #{app_to} -t #{api_to})
```

# 環境

* macOS 10.13.6
* Ruby 2.5.0
* cli-kintone 0.9.4

# 参考リンク

* [はじめようkintone コマンドライン](https://developer.cybozu.io/hc/ja/articles/115000297083)
* [クエリ指定](https://developer.cybozu.io/hc/ja/articles/202331474#step2)
* [kintone コマンドラインツールの使い方](https://developer.cybozu.io/hc/ja/articles/202957070-kintone-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9#step7)
* [定期実行でデータの同期を実現するスマートな方法 その1〜cli-kintone編〜
](https://developer.cybozu.io/hc/ja/articles/217964263-%E5%AE%9A%E6%9C%9F%E5%AE%9F%E8%A1%8C%E3%81%A7%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%90%8C%E6%9C%9F%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%81%AA%E6%96%B9%E6%B3%95-%E3%81%9D%E3%81%AE1-cli-kintone%E7%B7%A8-)
* [https://github.com/kintone/cli-kintone](https://github.com/kintone/cli-kintone)
* [https://developer.kintone.io/hc/en-us/articles/115002614853](https://developer.kintone.io/hc/en-us/articles/115002614853)
* [Open3ライブラリ](https://docs.ruby-lang.org/ja/latest/class/Open3.html)
* [Fileクラス](https://docs.ruby-lang.org/ja/latest/class/File.html)
* [CSVライブラリ](https://docs.ruby-lang.org/ja/latest/class/CSV.html)
* [StringIOクラス](https://docs.ruby-lang.org/ja/latest/class/StringIO.html)