kintone: Find Record ID By Specified Value
Identifies the record number that contains the specified value from the target column in a kintone app.
Configs
  • C1: Authorization Setting in which API Token is set *
  • C2: Basic Auth Setting (required if enabled on Kintone)
  • C3: Domain (such as xxxxx.kintone.com or xxxxx.cybozu.com) *
  • C4: Guest Space ID (required if the App is in a Guest Space)
  • C5: App ID *
  • C6: Search Query#{EL}
  • C7: Field Code of Record ID *
  • C8: Field Code of Target Col *
  • C9: String type data item for specified value *
  • C10: String type data item to save Record ID *
Script (click to open)


main();
function main(){
  //// == 工程コンフィグの参照 / Config Retrieving ==
  const auth = configs.get("conf_auth");
  const basic = configs.get("conf_basic");
  const domain = configs.get("conf_domain");
  const guestSpaceId = configs.get("conf_guestSpaceId");
  const appId = configs.get("conf_appId");
  const recordIdField = configs.get("conf_recordIdField");
  const targetField = configs.get("conf_targetField");
  const query = configs.get("conf_query");

  //// == ワークフローデータの参照 / Data Retrieving ==
  const apiToken = httpClient.getOAuth2Token( auth );

  //// == 演算 / Calculating ==
  const apiUri = determineApiUri( domain, guestSpaceId );
  checkAppId( appId );

  const initialParams = prepareInitialParams( appId, recordIdField, targetField, query );

  const records = []; // レコードオブジェクトを格納する配列
  const requestNum = 1; // 現時点での HTTP リクエスト回数
  getRecords( apiUri, apiToken, basic, initialParams, records, requestNum );

  const recordIdList = records.map( record => record[recordIdField].value );
  const targetList = records.map( record => record[targetField].value );

  const key = engine.findDataByNumber( configs.get("conf_key") ) + "";
  const recordIdDataDef = configs.get( "conf_recordId" );
  let row = -1;
  for (let i = 0; i < targetList.length; i++) {
    if (targetList[i] == key) {
      row = recordIdList[i];
      break;
    }
  }

  engine.setDataByNumber( recordIdDataDef, row + "");

}

/**
  * kintone REST API のレコード取得の URI を決定する
  * ドメインが空、または kintone のドメインとして不正な文字列であればエラーとする
  * @param {String} domain  ドメイン
  * @param {String} guestSpaceId  ゲストスペース ID
  * @return {String} apiUri  API の URI
  */
function determineApiUri( domain, guestSpaceId ) {
  checkDomain( domain );
  let apiUri;
  if ( guestSpaceId === "" || guestSpaceId === null ) {
    apiUri = `https://${domain}/k/v1/`;
  } else {
    if ( !isValidId(guestSpaceId) ) {
      throw "Invalid Guest Space ID.";
    }
    apiUri = `https://${domain}/k/guest/${guestSpaceId}/v1/`;
  }
  return apiUri;
}

/**
  * ドメインが空または不正な文字列であればエラーとする
  * @param {String} domain  ドメイン
  */
function checkDomain( domain ) {
  if ( domain === "" || domain === null ) {
    throw "Domain is empty.";
  }
  const reg = new RegExp( '^[0-9a-zA-Z-]{3,32}.(?:kintone.com|cybozu.com)$' );
  if ( !reg.test(domain) ) {
    throw "Invalid Kintone domain.";
  }
}

/**
  * アプリ ID が空または不正な文字列であればエラーとする
  * @param {String} appId  アプリ ID
  */
function checkAppId( appId ) {
  if ( appId === "" || appId === null ) {
    throw "App ID is empty.";
  }
  if ( !isValidId(appId) ) {
    throw "Invalid App ID.";
  }
}

/**
  * ID が有効か(自然数か)を判定する
  * @param {String} idString  ID の文字列
  * @return {Boolean}  有効な ID かどうか
  */
function isValidId( idString ) {
  const idReg = new RegExp( '^[1-9][0-9]*$' );
  return idReg.test( idString );
}

/**
  * 初回の GET リクエストのパラメータに使用する情報を準備する
  * @param {String} appId  アプリ ID
  * @param {String} recordIdField  レコード ID のフィールドコード
  * @param {String} targetField  対象列のフィールドコード
  * @param {String} query  検索クエリ
  * @return {Object} initialParams  リクエストのパラメータに使用する情報を格納した JSON オブジェクト
  *   プロパティ: {String} app  アプリ ID
  *              {Set<String>} fields  フィールドコードの集合
  *              {String} query  検索クエリ
  *              {Number} lastRecordId  検索済みの最後のレコード番号
  */
function prepareInitialParams( appId, recordIdField, targetField, query ) {
  const fields = new Set([ recordIdField, targetField ]);
  fields.add( '$id' ); // $id で並べ替えを行うため、取得フィールドに $id を追加する
  const initialParams = {
      app: appId,
      fields: fields,
      query: query,
      lastRecordId: 0
  };
  return initialParams;
}

/**
  * kintone REST API にレコード取得の GET リクエストを送信する
  * 未取得のレコードがなくなるまで再帰的に実行される
  * @param {String} apiUri  API の URI
  * @param {String} apiToken  API トークン
  * @param {String} basic  Basic 認証設定
  * @param {Object} params  GET リクエストのパラメータに使用する情報が格納されたオブジェクト
  *   プロパティ: {String} app  アプリ ID
  *              {Set<String>} fields  フィールドコードの集合
  *              {String} query  検索クエリ
  *              {Number} lastRecordId  検索済みの最後のレコード番号
  * @param {Array<Object>} records  レコードオブジェクトを格納する配列
  * @param {Number} requestNum  HTTP リクエスト回数
  */
function getRecords( apiUri, apiToken, basic, { app, fields, query, lastRecordId }, records, requestNum ) {
  // リクエスト回数の上限チェック
  if ( requestNum + 1 > httpClient.getRequestingLimit() ) {
    throw "HTTP requests exceed the limit.";
  }

  const LIMIT = 500; // 1回の GET リクエストで取得できるレコードの上限件数
  const getRecordsUri = `${apiUri}records.json`;
  let request = httpClient.begin()
    .queryParam("app", app)
    .header( "X-Cybozu-API-Token", apiToken );
  if ( basic !== "" && basic !== null ) {
    request = request.authSetting(basic);
  }
  // query パラメータの設定
  if ( query === "" || query === null ) {
    request = request.queryParam("query", `$id > ${lastRecordId} order by $id asc limit ${LIMIT}`);
  } else {
    request = request.queryParam("query", `( ${query} ) and $id > ${lastRecordId} order by $id asc limit ${LIMIT}`);
  }
  // fields パラメータの設定
  Array.from(fields.values()).forEach((fieldCode, i) => {
    request = request.queryParam(`fields[${i}]`, fieldCode);
  });
  const response = request.get( getRecordsUri );
  //when error thrown
  const responseStr = response.getResponseAsString();
  const status = response.getStatusCode();
  if (status >= 300) {
    engine.log(`---GET request--- ${status}\n${responseStr}\n`);
    throw `Failed to get records. status: ${status}`;
  }
  const json = JSON.parse(responseStr);
  Array.prototype.push.apply(records, json.records); // レコードオブジェクトを配列に追加
  requestNum++; // リクエスト回数を加算

  // レコード件数のチェック
  if ( records.length === 0 ) { // 該当するレコードが一件もなければエラー
    throw "No Choice Data found.";
  }
  if ( records.length > 150000 ) { // 15万件を超える場合はエラー
    throw "Number of Choice Data is over 150,000.";
  }

  // 再帰呼び出し
  if ( json.records.length === LIMIT ) {
    // 取得レコードの件数が LIMIT と同じ場合は、未取得のレコードが残っている場合があるので、
    // lastRecordId を更新し、getRecords を再帰呼び出しする
    lastRecordId = json.records[json.records.length - 1].$id.value;
    getRecords( apiUri, apiToken, basic, { app, fields, query, lastRecordId }, records, requestNum );
  }
}

  

Download

2021-11-11 (C) Questetra, Inc. (MIT License)
https://support.questetra.com/addons/kintone-find-record/
The Add-on import feature is available with Professional edition.
Freely modifiable JavaScript (ECMAScript) code. No warranty of any kind.

Notes

  • Returns -1 if there are no applicable rows.
  • To get an API token for your kintone app, go to the App Settings tab in the app’s settings page and go to API Token.

    Click Generate, select Permissions (Add records permission is required), and then click Save.

    Don’t forget to click “Update App” to apply the changes.
  • The guest space ID (if your app is in a guest space) and app ID of your kintone app can be found in the API token settings screen.

Capture

%d bloggers like this: