新規投稿
フォローする

他アプリのサブテーブル値を条件抽出 ⇒ サブテーブルへ取得値をコピー

いつもお世話になっております。
現状、自己解決できないエラーが発生しており、原因究明のアドバイスを頂けたらと思います。

・出張作業明細書(以降、Aアプリと記載)
・作業日報(以降、Bアプリと記載)

Bアプリから特定条件に一致するサブテーブルの値のみを抽出し、Aアプリのサブテーブルへデータコピーしたいと考えております。
データコピー作業は「Aアプリ側で完結」をさせる予定です。

https://developer.cybozu.io/hc/ja/community/posts/360047906752

上記QAなどを参照し、見よう見まねでコードを作成しましたが、現状「TypeError: Cannot read property 'value' of undefined」エラーが発生し先へ進めない状況です。

101行目、以下の[ii]後に記載された「value」でエラーが発生しているようなのですが、不思議なことにWatchでは問題なく中のデータが取得されていることが確認できます。

"作業開始": { "type": "DATETIME", "value": resp_pCostTable[ii].value["作業開始"].value },

素人ながらデバックツールも使用しつつ調べてはいるのですが、何が原因でエラーが発生しているのかを解明できずにおります。
もしかして大変初歩的なことをお聞きしているのかもしれませんが、皆様のお知恵をお貸し頂けましたら幸いです。
もし記載情報が不足しておりましたら、ご指摘ください。

以下に作成途中のコードを記載させて頂きます。
まだまだ修正していく予定ですが、コードの書き方がおかしいといった様なアドバイスなどもございましたら、あわせてご指摘頂けましたら嬉しいです。

(function() {
'use strict';

// 「Bアプリコピー」時の処理
kintone.events.on(["app.record.create.change.コピー",
"app.record.edit.change.コピー"],
function(event) {
var record = event.record;

///カーソル情報代入
var appID = 40; //データ取得元 BアプリID
var limit = 200;
var offset = 0;
var size = 100;
//Aアプリ情報代入
var pNo = record["工番"].value;
var reqStart = record["申請開始日"].value;
var reqEnd = record["申請終了日"].value;
var worker = record["出張作業者"].value;
var pCostTable = record["工数管理"].value;

function postCursor() {
var body = {
'app': appID,
'fields':["工数登録者","作業日","工数管理"],
//'query':「フィールドコード 演算子 条件」の順序で記述
         //Bアプリ:「作業日」 が Aアプリ:「申請開始日」~「申請終了日」の間 and
//Bアプリ:「工数登録者」 が Aアプリ:「出張作業者」と同じ and
//Bアプリ:サブテーブル工数管理「工番」 が Aアプリ:「工番」 と同じ
'query': '作業日 >= "'+ reqStart +'" and 作業日 <= "'+ reqEnd +'" and 工数登録者 = "'+ worker +'" and 工番 in ("'+ pNo +'") order by $id desc' ,
'limit': limit,
        'offset': offset,
'size': size,
};

// Bアプリデータ取得用のカーソル作成(thenを使うことで resp の中にデータが格納される)
return kintone.api(kintone.api.url('/k/v1/records/cursor', true), 'POST', body).then(function(resp) {
// 成功:カーソル作成
return resp.id;
// catch で取得失敗時のエラー制御
}).catch(function(error) {
// エラー発生時にエラー表示
return error;
});
}

function getRecordsFromCursor(cursorId, opt_records) {
var records = opt_records || [];
var body = {
'id': cursorId
};

// Bアプリからデータ取得(thenを使うことで resp の中にデータが格納される)
return kintone.api(kintone.api.url('/k/v1/records/cursor', true), 'GET', body).then(function(resp) {
// 成功:データを取得
records = records.concat(resp.records);
if (resp.next) {
return getRecordsFromCursor(cursorId, records);
}
return records;
// catch で取得失敗時のエラー制御
}).catch(function(error) {
// エラー発生時にエラー表示
return error;
});

}

postCursor().then(function(respCursorId) {
return getRecordsFromCursor(respCursorId);
}).then(function(respRecords) {
console.log(respRecords);

//Bアプリフィールド情報代入
for (var i = 0; i < respRecords.length; i++) {
var resp_pCostTable = respRecords[i]["工数管理"].value;

  //Aアプリ「工数管理」サブテーブルへ取得データセット
  for (var ii = 0; ii < respRecords.length; ii++) {
  pCostTable.unshift({
  value: {
  "作業開始": { "type": "DATETIME", "value": resp_pCostTable[ii].value["作業開始"].value },
  "作業終了": { "type": "DATETIME", "value": resp_pCostTable[ii].value["作業終了"].value },
  "休憩時間": { "type": "TIME", "value": resp_pCostTable[ii].value["休憩時間"].value },
  "作業時間": { "type": "CALC", "value": "" /*resp_pCostTable[ii].value["工数"].value*/ },
  "作業内容": { "type": "SINGLE_LINE_TEXT", "value": resp_pCostTable[ii].value["備考"].value },
  }
  });
  }

}

}).catch(function(error) {
console.log(error);
});

return event;

});
})();
0

8件のコメント

Avatar
TK

複数レコードのテーブルの値を、別アプリのレコードのテーブルに集約するって認識ですがあってますかね?

ここのループがおかしいかな?と思いました。

for (var ii = 0; ii < respRecords.length; ii++) {

for (var ii = 0; ii < resp_pCostTable.length; ii++) {
1
Avatar
KT

*TK 様*

いつもお世話になっております。
お礼の返信が遅くなり申し訳ありません。

TK様の仰られる通り、複数レコードのサブテーブル値を、別アプリのレコードのサブテーブルに集約するためのコードを作成中でございます。
頂きましたご指摘通り修正をいたしましたところ、エラーが発生しなくなりました。
本当にありがとうございます!
ご指摘頂いた点、大変初歩的な部分でミスをしておりお恥ずかしい限りです…。

エラーは発生しなくなりましたが、取得された値がサブテーブルへセットされないようですので、また色々と調べながら頑張って進めたいと思います。
この度もこのような拙い質問にご親切にお答え頂きまして誠にありがとうございました。

KTにより編集されました
0
Avatar
TK

非同期処理なので、レスポンスが返ってくる前にeventが返ってるのだと思います。

一つ目のfor文の前でkintone.app.record.get()して、for文抜けた後でsetすれば反映されるかと思います!

0
Avatar
KT

*TK 様*

重ね重ね誠にありがとうございます。
自身も調べつつ、TK様の仰られた位置にget/set文を配置してはみたものの、その位置に配置するとset文の(record)部が ReferenceError: record is not defined となってしまいました。

当記事(https://developer.cybozu.io/hc/ja/articles/201942014)に注意事項として

  • kintone.events.on のイベントハンドラ内で kintone.app.record.get および kintone.mobile.app.record.get を実行することはできません。 上記のイベントハンドラ内ではレコードデータの取得は引数のeventオブジェクトを、レコードデータの更新はeventオブジェクトのreturnを使用してください。

と記載されており、最後の return event 文でセットまで完了するのかと思っておりましたが、何か認識が誤っているようです。
素人知識のため、せっかくのアドバイスを頂いても一進一退の状態でもどかしい限りですが、もう少し類似の記事を調べつつ進めていきたいと思います!

KTにより編集されました
0
Avatar
TK

そのエラー文は recordの定義がされていない というエラーなので定義し忘れですね。

↓こんな感じで動きませんでしょうか?

   postCursor().then(function(respCursorId) {

return getRecordsFromCursor(respCursorId);

}).then(function(respRecords) {

console.log(respRecords);

var getRec = kintone.app.record.get();




//Bアプリフィールド情報代入

for (var i = 0; i < respRecords.length; i++) {

var resp_pCostTable = respRecords[i]["工数管理"].value;

  //Aアプリ「工数管理」サブテーブルへ取得データセット

  for (var ii = 0; ii < resp_pCostTable.length; ii++) {

// pCostTable.unshift({

getRec.record.record["工数管理"].value.unshift({ // recordがひとつ多いかもしれません!

  value: {

  "作業開始": { "type": "DATETIME", "value": resp_pCostTable[ii].value["作業開始"].value },

  "作業終了": { "type": "DATETIME", "value": resp_pCostTable[ii].value["作業終了"].value },

  "休憩時間": { "type": "TIME", "value": resp_pCostTable[ii].value["休憩時間"].value },

  "作業時間": { "type": "CALC", "value": "" /*resp_pCostTable[ii].value["工数"].value*/ },

  "作業内容": { "type": "SINGLE_LINE_TEXT", "value": resp_pCostTable[ii].value["備考"].value },

  }

  });

  }

}

kintone.app.record.set(getRec);

}).catch(function(error) {

console.log(error);

});




return event;
TKにより編集されました
0
Avatar
KT

*TK 様*

ご丁寧なソースコードの記載までして頂き、感謝の念が堪えません。
ご指摘の通り、どうやらset文の位置が原因でエラーが発生していたようでした。
お騒がせして申し訳ございません…。

記載頂きました通りにget/set文を配置いたしましたが、エラーは発生していないにもかかわらずやはりサブテーブルの値がセットされない状況で首を傾げております。
TK様には大変ご尽力頂きまして恐縮でございます。

 

(function() {
'use strict';

// 「作業日報コピー」押下時の処理
kintone.events.on(["app.record.create.change.コピー",
"app.record.edit.change.コピー"],
function(event) {
var record = event.record;

///カーソル情報代入
var appID = 40; //データ取得元「作業日報」アプリID
var limit = 200; //検索上限件数200件まで
var offset = 0; //検索開始位置0件目~ offset=レコードスキップ数
var size = 100; //カーソルサイズ100件ずつ繰上げつつ検索
//出張作業明細書アプリ情報代入
var pNo = record["工番"].value;
var reqStart = record["申請開始日"].value;
var reqEnd = record["申請終了日"].value;
var worker = record["出張作業者"].value;
var pCostTable = record["工数管理"].value;

function postCursor() {
var body = {
'app': appID,
'fields':["工数登録者","作業日","工数管理"],
//'query':「フィールドコード 演算子 条件」の順序で記述
//作業日報:「出張」チェックボックス チェック and
//作業日報:「作業日」 が 出張作業明細書:「申請開始日」~「申請終了日」の間 and
//作業日報:「工数登録者」 が 出張作業明細書:「出張作業者」と同じ and
//作業日報:工数管理サブテーブル内「工番」 が 出張作業明細書:「工番」 と同じ
'query': '作業日 >= "'+ reqStart +'" and 作業日 <= "'+ reqEnd +'" and 工数登録者 = "'+ worker +'" and 工番 in ("'+ pNo +'") order by $id desc' ,
'limit': limit,
'offset': offset,
'size': size,
};

// データ取得用のカーソル作成(thenを使うことで resp の中にデータが格納される)
return kintone.api(kintone.api.url('/k/v1/records/cursor', true), 'POST', body).then(function(resp) {
// 成功:カーソル作成
return resp.id;

// catch で取得失敗時のエラー制御
}).catch(function(error) {
// エラー発生時にエラー表示
return error;
});
}

function getRecordsFromCursor(cursorId, opt_records) {
var records = opt_records || [];
var body = {
'id': cursorId
};

// 「作業日報」アプリからデータ取得(thenを使うことで resp の中にデータが格納される)
return kintone.api(kintone.api.url('/k/v1/records/cursor', true), 'GET', body).then(function(resp) {
// 成功:データを取得
records = records.concat(resp.records);
if (resp.next) {
return getRecordsFromCursor(cursorId, records);
}
return records;

// catch で取得失敗時のエラー制御
}).catch(function(error) {
// エラー発生時にエラー表示
return error;
});

}

//コンソールへ取得情報格納
postCursor().then(function(respCursorId) {
return getRecordsFromCursor(respCursorId);
}).then(function(respRecords) {
console.log(respRecords);

//set用レコード情報の取得
var getRec = kintone.app.record.get();

//コンソールへ格納した「作業日報」アプリフィールド情報代入
for (var i = 0; i < respRecords.length; i++) {
var resp_pCostTable = respRecords[i]["工数管理"].value;

//「出張作業明細書」アプリ「工数管理」サブテーブルへ取得データセット
for (var ii = 0; ii < resp_pCostTable.length; ii++) {
getRec.record["工数管理"].value.unshift({
value: {
"作業開始": { "type": "DATETIME", "value": resp_pCostTable[ii].value["作業開始"].value },
"作業終了": { "type": "DATETIME", "value": resp_pCostTable[ii].value["作業終了"].value },
"休憩時間": { "type": "TIME", "value": resp_pCostTable[ii].value["休憩時間"].value },
"作業時間": { "type": "CALC", "value": "" /*resp_pCostTable[ii].value["工数"].value*/ },
"作業内容": { "type": "SINGLE_LINE_TEXT", "value": resp_pCostTable[ii].value["備考"].value },
}
});
}

}

//取得したset用レコード情報をセット
kintone.app.record.set(getRec);

}).catch(function(error) {
console.log(error);
});

return event;

});
})();
KTにより編集されました
0
Avatar
TK

一か所変え忘れあります!

ここも変えてください!

for (var ii = 0; ii < resp_pCostTable.length; ii++) {
  // pCostTable.unshift({
  getRec.record.record["工数管理"].value.unshift({ // recordがひとつ多いかもしれません!
TKにより編集されました
1
Avatar
KT

*TK 様*

いつもお世話になっております。
TK様にご指摘頂きました通り変更いたしましたところ、希望通りBアプリから取得されたデータのセットが行えました!!
※上記のコードもあわせて修正いたしました。

getRec.record["工数管理"].value.unshift({ 文の追加

ここ半月ほど進まず悩んでいた現象でしたため、本当に感激しております!
同時進行で、同じように他アプリの複数レコードからデータ抽出⇒計算⇒セットを行うアプリ制作を行っておりますため、この度ご教授頂きました方法を参考にして作成を進めて参りたいと思います。

TK様にはいつも沢山のアドバイスや知識をご教授頂きまして、重ねて御礼申し上げます。
きちんと自身の知識も増やしながら、今後も勉強を進めて参ります。
誠にありがとうございます!

1
ログインしてコメントを残してください。