
Microsoft Lists: Search List Items
This item searches list items in the specified list on Microsoft Lists.
Basic Configs
- Step Name
- Note
Configs for this Auto Step
- conf_OAuth2
- C1: OAuth2 Setting *
- conf_SiteUrl
- C2: SharePoint Site URL *
- conf_ListTitle
- C3: List Title *
- conf_Filter
- C4: Filter#{EL}
- conf_Ids
- C5: Data item to save List Item IDs
- conf_ColumnName1
- C-K1: Lists Field Name of Column 1
- conf_ColumnValues1
- C-V1: Data item to save values of Column 1
- conf_ColumnName2
- C-K2: Lists Field Name of Column 2
- conf_ColumnValues2
- C-V2: Data item to save values of Column 2
Notes
- The SharePoint Site URL is the part before
/Listsof the List URL- When the List is in My lists, it looks like
https://{sub-domain}-my.sharepoint.com/personal/{user-identifier}_{domain}_onmicrosoft_com - When the List is in a SharePoint site, it looks like
https://{sub-domain}.sharepoint.com/sites/{site-identifier}
- When the List is in My lists, it looks like
- Refer to the Microsoft Graph Documentation to know about the filter format
- When the number of List Items exceeds 5000, it is required to add indexes of the columns to filter
- There are some ways to get field names of the columns :
- When you export CSV with schema of the List, the field names are shown in
Nameproperty of each column’s schema - When you sort the the List by a column on WebUI, the field name of the column is included in the URL in the form of
sortField={fieldName}
- When you export CSV with schema of the List, the field names are shown in
- Supported Microsoft Lists column types are : Single line of text, Number, Yes/No, Date and time, Choice (when multiple selections are disabled), Currency
Capture

See Also
Script (click to open)
- An XML file that contains the code below is available to download
- microsoft-lists-listitem-search.xml (C) Questetra, Inc. (MIT License)
- If you are using Professional, you can modify the contents of this file and use it as your own add-on auto step
// OAuth2 config sample at [OAuth 2.0 Setting]
// - Authorization Endpoint URL: https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/authorize
// - Token Endpoint URL: https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token
// - Scope: https://graph.microsoft.com/Sites.ReadWrite.All offline_access
// - Consumer Key: (Get by Microsoft Azure Active Directory)
// - Consumer Secret: (Get by Microsoft Azure Active Directory)
const GRAPH_URI = 'https://graph.microsoft.com/v1.0/';
const MAX_PAGE_SIZE = 5000; // 一度のリクエストで取得できるリストアイテムの最大数
const main = () => {
//// == 工程コンフィグの参照 / Config Retrieving ==
const oauth2 = configs.getObject('conf_OAuth2');
const siteUrl = retrieveSiteUrl();
const listTitle = configs.get('conf_ListTitle');
const filter = configs.get('conf_Filter');
const {idDef, columnNames, columnDefs, singleLineFlag} = retrieveColumnNamesAndDataDefs();
//// == 演算 / Calculating ==
const siteId = getSiteIdByUrl(oauth2, siteUrl);
if (columnNames.length > 0) {
checkColumns(oauth2, siteId, listTitle, columnNames);
}
const listItems = getListItems(oauth2, siteId, listTitle, filter, columnNames, singleLineFlag);
//// == ワークフローデータへの代入 / Data Updating ==
saveData(listItems, idDef, columnNames, columnDefs);
};
/**
* 工程コンフィグからサイトの URL を取得する
* @returns {String} サイトの URL
*/
const retrieveSiteUrl = () => {
let siteUrl = configs.get('conf_SiteUrl');
// 末尾にスラッシュがある場合、削除
if (siteUrl.endsWith('/')) {
siteUrl = siteUrl.slice(0, -1);
}
return siteUrl;
};
/**
* 工程コンフィグから列の名前、保存先データ項目を取得する
* 以下の場合はエラー
* - 名前、保存先データ項目の片方だけが指定されている列がある
* - 保存先データ項目がひとつも指定されていない
* @returns {Object} result
* @returns {DataDefinitionView} result.idDef ID 保存先データ項目
* @returns {Array<String>} result.columnNames 列の名前
* @returns {Array<DataDefinitionView>} result.columnDefs 列の値の保存先データ項目
* @returns {boolean} result.singleLineFlag 保存先データ項目のうちひとつでも単一行のものがあれば true
*/
const retrieveColumnNamesAndDataDefs = () => {
const columnNames = [];
const columnDefs = [];
let singleLineFlag = false;
for (let i = 0; i < 2; i++) {
const columnName = configs.get(`conf_ColumnName${i + 1}`);
const columnDef = configs.getObject(`conf_ColumnValues${i + 1}`);
if (columnName === '' && columnDef === null) {
continue;
} else if (columnName !== '' && columnDef !== null) {
columnNames.push(columnName);
columnDefs.push(columnDef);
if (columnDef.matchDataType('STRING_TEXTFIELD')) {
singleLineFlag = true;
}
} else {
throw new Error(`Name and data item for Column ${i + 1} must be specified at the same time.`);
}
}
const idDef = configs.getObject('conf_Ids');
if (idDef === null && columnDefs.length === 0) {
throw new Error('No data item to save the result.');
}
if (idDef !== null && idDef.matchDataType('STRING_TEXTFIELD')) {
singleLineFlag = true;
}
return {idDef, columnNames, columnDefs, singleLineFlag};
};
/**
* サイトのメタデータを取得し、siteId を返す
* APIの仕様: https://docs.microsoft.com/ja-jp/onedrive/developer/rest-api/api/shares_get?view=odsp-graph-online
* @param {AuthSettingWrapper} oauth2 OAuth2 設定情報
* @param {String} siteUrl SharePoint サイトの URL
* @returns {String} siteId
*/
const getSiteIdByUrl = (oauth2, siteUrl) => {
// encoding sharing URL
const encodedSharingUrl = encodeSharingUrl(siteUrl);
// preparing for API Request
const response = httpClient.begin()
.authSetting(oauth2)
.queryParam('select', 'id')
.get(`${GRAPH_URI}shares/${encodedSharingUrl}/site`);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 200) {
engine.log(responseStr);
throw new Error(`Failed to get site info. status: ${status}`);
}
return JSON.parse(responseStr).id;
};
/**
* 共有URLを unpadded base64url 形式にエンコードする
* @param {String} sharingUrl 共有URL
* @returns {String} encodedSharingUrl エンコードされた共有URL
*/
const encodeSharingUrl = (sharingUrl) => {
let encodedSharingUrl = base64.encodeToUrlSafeString(sharingUrl);
while (encodedSharingUrl.slice(-1) === '=') {
encodedSharingUrl = encodedSharingUrl.slice(0, -1);
}
return `u!${encodedSharingUrl}`;
};
/**
* リストの列のメタデータを取得し、指定した名前の列の存在と型を確認する
* @param {AuthSettingWrapper} oauth2 OAuth2 設定情報
* @param {String} siteId SharePoint サイトの ID
* @param {String} listTitle リストの名前
* @param {Array<String>} columnNames 列の名前
*/
const checkColumns = (oauth2, siteId, listTitle, columnNames) => {
const url = `${GRAPH_URI}sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listTitle)}/columns`;
const response = httpClient.begin()
.authSetting(oauth2)
.queryParam('$select', 'name,text') // 複数行のテキスト型をエラーにするため、text プロパティを取得
// $filter, $search, $top パラメータは効かない
.get(url);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 200) {
engine.log(responseStr);
throw new Error(`Failed to get columns. status: ${status}`);
}
const columns = JSON.parse(responseStr).value;
columnNames.forEach(columnName => {
findAndCheckColumn(columns, columnName);
});
};
/**
* 列の存在と型を確認する
* 列が存在しない場合、テキスト型で複数行を許可している場合はエラーにする
* @param {Array<Object>} columns 列のメタデータ一覧
* @param {String} name 列の名前
*/
const findAndCheckColumn = (columns, name) => {
const column = columns.find((column) => column.name === name);
if (column === undefined) {
throw new Error(`Column '${name}' not found.`);
}
if (column.text !== undefined && column.text.allowMultipleLines) {
throw new Error(`'${name}' is a text column which can contain a multi-line text.`);
}
};
/**
* リストアイテムを検索し、JSONオブジェクトを返す
* @param {AuthSettingWrapper} oauth2 OAuth2 設定情報
* @param {String} siteId SharePoint サイトの ID
* @param {String} listTitle リストの名前
* @param {String} filter フィルタ
* @param {Array<String>} columnNames 列の名前
* @param {boolean} singleLineFlag 保存先データ項目のうちひとつでも単一行のものがあれば true
* @returns {Array<Object>} 検索結果
*/
const getListItems = (oauth2, siteId, listTitle, filter, columnNames, singleLineFlag) => {
const url = `${GRAPH_URI}sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listTitle)}/items`;
let request = httpClient.begin()
.authSetting(oauth2)
// インデックスを作成していないフィールドでもフィルタできるように、Prefer ヘッダを指定
// ただし、リストアイテムの総数が多すぎる(5000 件以上)とエラーになる
.header('Prefer', 'HonorNonIndexedQueriesWarningMayFailRandomly')
.queryParam('$select', 'id')
.queryParam('$top', `${MAX_PAGE_SIZE}`)
// $count パラメータは非対応
// $orderby パラメータはあえて指定しない。デフォルトの ID 順のまま取得する
.queryParam('$filter', filter);
if (columnNames.length > 0) {
request = request.queryParam('$expand', `fields($select=${columnNames.join(',')})`);
}
const response = request.get(url);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 200) {
engine.log(responseStr);
throw new Error(`Failed to get list items. status: ${status}`);
}
const listItems = JSON.parse(responseStr).value;
if (listItems.length === 0) {
throw new Error('No list items found.');
}
// 本来は一度のリクエストで検索結果を取得しきれなかった場合にエラーにしたいが、$count パラメータが使用不可なので、
// 取得された件数が上限値と同じ場合にエラーにする
if (listItems.length === MAX_PAGE_SIZE) {
throw new Error(`The number of results reached ${MAX_PAGE_SIZE}.`);
}
if (singleLineFlag && listItems.length > 1) {
throw new Error('Multiple list items were found while the data item to save the result is single-line.');
}
return listItems;
};
/**
* データ項目への保存
* @param {Array<Object>} listItems リストアイテム
* @param {DataDefinitionView} idDef ID 保存先データ項目
* @param {Array<String>} columnNames 列の名前
* @param {Array<DataDefinitionView>} columnDefs 列の値の保存先データ項目
*/
const saveData = (listItems, idDef, columnNames, columnDefs) => {
setData(idDef, listItems.map((item) => item.id).join('\n'));
columnNames.forEach((columnName, index) => {
setData(columnDefs[index], stringifyColumnValues(listItems, columnName));
});
};
/**
* 列の値を文字列化する
* @param listItems
* @param columnName
*/
const stringifyColumnValues = (listItems, columnName) => {
const columnValues = listItems.map((item) => item.fields[columnName])
.map(columnValue => {
if (columnValue === undefined || columnValue === null) {
return '';
}
const supportedPrimitiveTypes = ['string', 'number', 'boolean'];
if (supportedPrimitiveTypes.includes(typeof columnValue)) {
return columnValue.toString();
}
// 配列や JSON オブジェクトの場合、エラー
throw new Error(`Failed to stringify the value of Column '${columnName}'. It is not a string, number, nor boolean.`);
});
return columnValues.join('\n');
};
/**
* データ項目への保存
* @param {DataDefinitionView} def 保存先データ項目
* @param {Object} data 保存するデータ
*/
const setData = (def, data) => {
if (def !== null) {
engine.setData(def, data);
}
};