CSV指定でファイル一括アップロード

CSV指定で添付ファイルを一括アップロードするコードをご紹介します.

動作環境

Node.js v12以上で動作します.

用意するファイル

sample.csv

先頭行はフィールド名,文字コードはShift_JIS,区切り文字はカンマ「,」,囲み文字はダブルクォート「"」としてください. 添付ファイルは,main.jsからの相対パスで指定してください. 添付ファイルを複数指定する場合は,カンマ「,」で区切ってください.

・例

"レコード番号","文字列 (1行)","数値","ラジオボタン","添付ファイル"
"2","abc","1","sample1","sample_image1.jpg"
"1","a","1","sample1","sample_image1.jpg,sample_image2.jpg"

※チェックボックス,複数選択,ユーザー選択,組織選択,グループ選択,サブテーブルには非対応です. kintoneのファイル書き出し機能で出力したCSVファイルを利用する場合は,上記フィールドを除外してください.

main.js

9~18行目は適宜変更してください.

(async()=\>{constutil=require('util');constfs=require('fs');consticonv=require('iconv-lite');const{KintoneRestAPIClient}=require('@kintone/rest-api-client');constcsvParse=require('csv-parse/lib/sync');constreadFile=util.promisify(fs.readFile);constclient=newKintoneRestAPIClient({baseUrl:'https://\*\*\*\*.cybozu.com',//kintoneのURLauth:{username:'\*\*\*\*',//kintoneのログイン名password:'\*\*\*\*',//kintoneのパスワード},});constapp= **** ;//アプリIDconstfileName='sample.csv';//CSVファイルのパスconstreverse=true;//データをCSVの逆順に登録するか否かconstformFields=awaitclient.app.getFormFields({app});constdatas=csvParse(iconv.decode(Buffer.from(awaitreadFile(fileName),'binary'),'Shift\_JIS'),{delimiter:',',rowDelimiter:'auto',quote:'"'});constheaders=datas[0].reduce((headers,header,index)=\>{constproperty=Object.values(formFields.properties).find(property=\>property.label===header);if(['RECORD\_NUMBER','\_\_ID\_\_','\_\_REVISION\_\_','CREATOR','MODIFIER','CREATED\_TIME','UPDATED\_TIME','CATEGORY','STATUS','STATUS\_ASSIGNEE',].includes(property.type))returnheaders;headers.push({index,type:property.type,code:property.code});returnheaders;},[]);constfiles=awaitPromise.all(datas.slice(1).map(data=\>headers.filter(header=\>header.type==='FILE').map(header=\>data[header.index].split(','))).flat(2).map(path=\>client.file.uploadFile({file:{path}})));letfileIndex=0;constrecords=datas.slice(1).map(data=\>headers.reduce((record,header)=\>{if(header.type==='FILE'){record[header.code]={value:data[header.index].split(',').map(filePath=\>{returnfiles[fileIndex++]})};}else{record[header.code]={value:data[header.index]};}returnrecord;},{}));if(reverse)records.reverse();awaitclient.record.addAllRecords({app,records});console.log('レコードを追加しました.');})();

必要パッケージのインストール

$ npm i iconv-lite csv-parse @kintone/rest-api-client

実行

$ node main.js

node.jsも初心者ですが、インストールを終え、node main.js実行時、

(node:5744) UnhandledPromiseRejectionWarning: Error: Cannot find module ‘iconv-lite’
Require stack:

  • D:\WK\main.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
    at Function.Module._load (internal/modules/cjs/loader.js:725:27)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at D:\WK\main.js:4:17
    at Object.<anonymous> (D:\WK\main.js:80:3)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions…js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    (Use node --trace-warnings ... to show where the warning was created)
    (node:5744) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
    (node:5744) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

となります。

npm install -g iconv-lite

は実行しましたが、同じです。

kintone移行検討中さん

-gオプションを外して,iconv-liteをローカルインストールしても動きませんか?

npm i iconv-lite

もしグローバルにインストールするのであれば,環境変数にグローバルのnode_modulesのパスを追加する必要があります.
https://qiita.com/takiru/items/391817ea6c62837ace5a

iconv-lite

@kintone/rest-api-client

csv-parse

をインストールして無事動作しました。ありがとうございます。

ユーザー名を移行するにあたって、考え方として1行テキストで移行とユーザー選択を考えていますが、ユーザー選択に移行するには、どのような手続きが必要でしょうか?表示名 or ログイン名、複数値など考え方について教えてください。

よく調べもしないで、すいませんでした。

ログイン名で改行をつけるイメージですね。

これで、いろいろ試してみます。

ありがとうございました。

やはり一癖ありそうです。

UIからの操作ではデータ形式も確認できたのですが、JSからはエラーになります。

エクスポートデータでは複数値は改行でしたが、スクリプト例ではカンマだったと思います。

どちらでもよいのでしょうか。

UIからはフィールドの位置とレコード番号のキーの解除が必要ですが、スクリプトでは特に意識しなくてもよいのでしょうか。

現在の課題として

・ユーザー選択

・作成者

・作成日時

・更新者

・更新日時

の移行について検証中です。

調べていると、このnode.jsの話題とJavascriptによる話題が全く別次元に見えるのですが、バッチ操作と画面からの操作と考えればよいのでしょうか?100件ごとのループなど制限は同じでしょうか?

kintone移行検討中さん

kintoneのデフォルトの「ファイルから読み込む」という機能とは別物になります.

本記事の機能は,kintone REST APIを利用して作成しています.
記事に注釈として書いておりますが,記事内のコードでは「チェックボックス,複数選択,ユーザー選択,組織選択,グループ選択,サブテーブル」には非対応です.

「ユーザー選択」に対応させる場合は,登録するレコードがこちらのユーザー選択の形式になるようにCSVを整形するコードを追加することになります.

main.jsの65行目で登録するレコードを定義しているので,そちらを変更します.

const records = datas.slice(1).map(data => headers.reduce((record, header) => {
  if(header.type === 'FILE') {
    record[header.code] = {
      value: data[header.index].split(',').map(filePath => {
        return files[fileIndex++]
      })
    };
  } else if(header.type === 'USER_SELECT') {
    record[header.code] = {
      value: data[header.index].split(',').map(code => {
        return {code}
      })
    };
  } else {
    record[header.code] = {value: data[header.index]};
  }
  return record;
}, {}));

CSVは,ユーザー選択を複数入力する場合はカンマ区切りで入力してください.

"レコード番号","文字列 (1行)","数値","ラジオボタン","添付ファイル","ユーザー選択"
"2","abc","1","sample1","sample_image1.jpg","user1,user2"
"1","a","1","sample1","sample_image1.jpg,sample_image2.jpg","user3"

「作成者,作成日時,更新者,更新日時」については,自動的に入力される値であり,こちらから任意に入力することはできません.
これは,kintoneのデフォルトの「ファイルから読み込む」という機能においても同じかと思います.

レコード数については,無制限です.
@kintone/rest-api-clientのaddAllRecordsメソッドがうまく処理してくれています.

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。