Stream - スコープ指定、グローバル
Stream API は、レコードなどのアイテムのストリームを操作します。例えば、forEach() メソッドを使用して、GlideQuery API によって返されるストリーム内の各レコードのステータスを更新できます。
Stream オブジェクトは以下の方法で取得できます。
- コンストラクターを使用して Stream オブジェクトをインスタンス化する。
- GlideQuery.select() メソッドから Stream オブジェクトを返します。詳細については、「GlideQuery」を参照してください。
このメソッドは静的であり、fromArray() クラスのインスタンスを必要としません。
スコープ対象またはグローバルサーバー側スクリプトで Stream API を使用します。この API には GlideQuery [com.sn_glidequery] プラグインが必要です。
実装
この API は、メソッド呼び出しが連鎖していて、各メソッドが前のメソッドで返された結果に基づいて構築されるビルダーパターン。メソッドを使用してクエリの属性を定義します。メソッドは、ターミナルメソッド (クエリ結果を返すメソッド) を呼び出すまで実行されないため、クエリを実行する前にクエリの要件を定義できます。 内の GlideQuery および Optional API と連動します。
クエリが単一のレコードを返す場合、システムは Optional オブジェクトに結果をラップします。クエリがレコードのストリームを返す場合、システムは Stream オブジェクトに結果をラップします。これらのオブジェクトを使用すると、各 API で一連のメソッドを使用して結果を管理できます。
たとえば、この スクリプトはタスクテーブルに対してクエリを実行し、レコードを優先度別にグループ化して、合計再アサイン回数が 4 を超える各優先度を返します。
var query = new global.GlideQuery('task')
.where('active', true) //Returns new GlideQuery object with a "where" clause.
.groupBy('priority') //Returns new GlideQuery object with a "group by" clause.
.aggregate('sum', 'reassignment_count') //Returns new GlideQuery object with a "sum(reassignment_count)" clause.
.having('sum', 'reassignment_count', '>', 4) //Returns new GlideQuery object with a "having reassignment_count > 4" clause.
.select() //Returns a stream of records wrapped in a Stream object.
.forEach(function (priority){ //Terminal method in the Stream class that executes the query and returns the result.
gs.info("Priority " + priority.group.priority + ": " + priority.sum.reassignment_count + " reassignments");
});Priority 1: 11 reassignments
Priority 3: 6 reassignments
Priority 5: 5 reassignmentsターミナルメソッド
パフォーマンス上の理由から、クエリーはターミナルメソッドを呼び出すときにのみデータをフェッチします。Stream クラスのターミナルメソッドは次のとおりです。
Stream - Stream(関数 nextFn)
Stream オブジェクトをインスタンス化します。
このコンストラクターを使用する代わりに、GlideQuery API を使用して、クエリーに基づいて Stream オブジェクトを返すことができます。
| 名前 | タイプ | 説明 |
|---|---|---|
| nextFn | 関数 | ストリーム内の次のアイテムを取得する関数。 |
この例では、乱数ジェネレーターに基づいて Stream オブジェクトを作成する方法を示します。無限ループが発生しないように、必ず limit() メソッドを含めてください。
new Stream(Math.random)
.map(Math.round)
.map(function (num) {
return num === 1 ? 'heads' : 'tails';
})
.limit(10)
.forEach(gs.info)
出力:
*** Script: tails
*** Script: heads
*** Script: tails
*** Script: heads
*** Script: tails
*** Script: heads
*** Script: tails
*** Script: tails
*** Script: tails
*** Script: tails
Stream - chunk(数字 count)
結果をアレイのバッチで返します。それぞれのアレイには、メソッドに渡された数のレコードが含まれています。
| 名前 | タイプ | 説明 |
|---|---|---|
| count | 数字 | ストリームから返された各アレイ内のレコードの数。 |
| タイプ | 説明 |
|---|---|
| ストリーム | レコードなどのアイテムのストリームを操作するために使用されるオブジェクト。 |
この例は、テーブルをクエリーし、結果をアレイのバッチにチャンクする方法を示しています。
var chunkResult = new GlideQuery('cmdb_ci_hardware')
.select('asset', 'purchase_date')
.limit(10)
.chunk(5) //Returns arrays of 5 sys_ids at a time
.forEach(function (chunk){
gs.info(JSON.stringify(chunk, null, 2));
});
出力:
*** Script: [
{
"asset": "2fa9680d3790200044e0bfc8bcbe5dfb",
"purchase_date": "2022-02-28",
"sys_id": "2ba9680d3790200044e0bfc8bcbe5dfc"
},
{
"asset": "73c1fa8837f3100044e0bfc8bcbe5ded",
"purchase_date": "2017-12-05",
"sys_id": "b4fd7c8437201000deeabfc8bcbe5dc1"
},
{
"asset": "cbc1ba8837f3100044e0bfc8bcbe5dad",
"purchase_date": "2017-12-05",
"sys_id": "25fd3c8437201000deeabfc8bcbe5dea"
},
{
"asset": "8fc1ba8837f3100044e0bfc8bcbe5da9",
"purchase_date": null,
"sys_id": "108a9205c611227500786e160f9d343e"
},
{
"asset": "27c1fa8837f3100044e0bfc8bcbe5dd8",
"purchase_date": "2017-06-06",
"sys_id": "a9a2d111c611227601fb37542399caa8"
}
]
*** Script: [
{
"asset": "93c1fa8837f3100044e0bfc8bcbe5d30",
"purchase_date": "2017-12-05",
"sys_id": "6b43105c37301000deeabfc8bcbe5db2"
},
{
"asset": "a2c0b1213784200044e0bfc8bcbe5de3",
"purchase_date": "2017-12-05",
"sys_id": "aac0b1213784200044e0bfc8bcbe5de3"
},
{
"asset": "33c1fa8837f3100044e0bfc8bcbe5def",
"purchase_date": "2017-12-05",
"sys_id": "d0e8761137201000deeabfc8bcbe5da7"
},
{
"asset": "53c1fa8837f3100044e0bfc8bcbe5d1f",
"purchase_date": "2017-12-05",
"sys_id": "53fdbc8437201000deeabfc8bcbe5d10"
},
{
"asset": "f1c031213784200044e0bfc8bcbe5de0",
"purchase_date": "2017-12-05",
"sys_id": "71c031213784200044e0bfc8bcbe5de1"
}
]
この例は、ID のバッチを使用して子クエリーを作成する方法を示しています。chunk() メソッドを使用した後に flatMap() メソッドを呼び出すと、個々のレコードではなくレコードのバッチが反復処理されます。
var chunkResult = new global.GlideQuery('cmdb_ci_hardware')
.select('sys_id')
.map(function (device) { return device.sys_id; })
.chunk(5) //Returns arrays of 5 sys_ids at a time
.flatMap(function (deviceIds) {
return new GlideQuery('cmdb_sam_sw_install')
.where('installed_on', 'IN', deviceIds)
.select('software_model', 'installed_on');
})
gs.info(JSON.stringify(chunkResult)); Stream - every(関数 predicate)
Stream オブジェクト内の全アイテムに述語関数を適用します。述語がストリーム内の全アイテムに対して true を返す場合、メソッドは true を返します。述語がストリーム内のいずれかのアイテムに対して false を返す場合、メソッドは false を返します。
| 名前 | タイプ | 説明 |
|---|---|---|
| predicate | 関数 | Stream オブジェクト内の全レコードまたはアイテムに適用する述語関数。この関数は、ストリーム内の各アイテムを入力として受け取り、ブール値を返す必要があります。 |
| タイプ | 説明 |
|---|---|
| ブーリアン | 述語関数がストリーム内の全アイテムに対して true を返すかどうかを示すフラグ。 有効な値:
|
この例では、ストリーム内の全アイテムに述語関数を適用する方法を示します。
var hasOnlyShortDescriptions = new global.GlideQuery('task')
.whereNotNull('description')
.select('description')
.every(function (t) {
return t.description.length < 10;
});
gs.info(hasOnlyShortDescriptions);
出力:
false
Stream - filter(関数 predicate)
Stream オブジェクト内の各アイテムに述語関数を適用します。述語が true を返す場合、メソッドは true を返します。述語が false を返す場合は、空の Stream オブジェクトを返します。
パフォーマンスを向上させるには、可能であれば、GlideQuery クラスでこのメソッドではなく、where()、whereNotNull()、および whereNull() メソッドを使用します。「GlideQuery()」を参照してください。
| 名前 | タイプ | 説明 |
|---|---|---|
| predicate | 関数 | Stream オブジェクト内の全レコードまたはアイテムに適用する述語関数。この関数は、ストリーム内の各アイテムを入力として受け取り、ブール値を返す必要があります。 |
| タイプ | 説明 |
|---|---|
| ストリーム | レコードなどのアイテムのストリームを操作するために使用されるオブジェクト。 |
この例は、定義済みフィルターに対してタスクテーブル内のすべてのレコードを照合する方法を示しています。レコードがフィルターに一致すると、レコードのストリームが返されます。一致しなかった場合は、空の Stream オブジェクトが返されます。
var shoutingTasks = new global.GlideQuery('task')
.whereNotNull('description')
.select('description')
.filter(function (task) {
return task.description.toUpperCase() === task.description;
})
Stream - find(関数 predicate)
述語関数に一致する Stream オブジェクトの最初のレコードまたはアイテムを返します。述語関数が指定されていない場合、このメソッドはストリーム内の最初のレコードまたはアイテムを返します。
| 名前 | タイプ | 説明 |
|---|---|---|
| predicate | 関数 | オプション。Stream オブジェクト内のアイテムに適用する述語関数。この関数は、ストリーム内の各アイテムを入力として受け取り、ブール値を返す必要があります。 |
| タイプ | 説明 |
|---|---|
| オプション | 返されたレコードを含むオブジェクト。 |
この例は、ストリームから最初のレコードを返す方法を示しています。
var UserOptional = new global.GlideQuery('sys_user')
.where('active', true)
.where('company.name', 'ServiceNow')
.select()
.find()
.map(function (user) {
return JSON.stringify(user);
})
gs.info(UserOptional);
出力:
Optional<{"sys_id":"babb4639b76233004fbc2089ee11a97f"}>
Stream - flatMap(関数 fn)
Stream 内の全アイテムに関数を適用します。反復可能な別のストリームを返します。
関数によってレコードの 2 番目のストリームが返される場合は、map() の代わりにこのメソッドを使用します。
| 名前 | タイプ | 説明 |
|---|---|---|
| fn | 関数 | Stream オブジェクトを返すクエリーの結果に適用する関数。 |
| タイプ | 説明 |
|---|---|
| ストリーム | 関数を適用した後に更新されたレコードのストリームを含むオブジェクト。 |
この例では、ユーザーテーブルをクエリーして、その結果から子クエリーを作成する方法を示します。この例では N+1 クエリーを実行するため、パフォーマンスの問題が発生する可能性があります。このユースケースを本番環境で使用しないようにしてください。
var records = new global.GlideQuery('sys_user')
.where('last_login', '>', '2015-12-31')
.select('first_name', 'last_name')
.flatMap(function (u) {
return new global.GlideQuery('task')
.where('closed_by', u.sys_id)
.select('closed_at', 'description')
.map(function (t) {
return {
first_name: u.first_name,
last_name: u.last_name,
description: t.description,
closed_at: t.closed_at
};
});
})
.limit(5)
.toArray(100);
gs.info(JSON.stringify(records));
出力:
[
{
"first_name":"System",
"last_name":"Administrator",
"description":null,
"closed_at":"2020-08-23 13:14:56"
},
{
"first_name":"System",
"last_name":"Administrator",
"description":null,
"closed_at":"2020-08-23 13:07:43"
},
{
"first_name":"System",
"last_name":"Administrator",
"description":null,
"closed_at":"2020-06-15 06:59:05"
},
{
"first_name":"System",
"last_name":"Administrator",
"description":null,
"closed_at":"2020-08-23 13:07:33"
},
{
"first_name":"System",
"last_name":"Administrator",
"description":null,
"closed_at":"2020-08-23 13:07:14"
}
]
Stream - forEach(関数 fn)
指定された関数をストリーム内の各レコードまたはアイテムに適用します。
| 名前 | タイプ | 説明 |
|---|---|---|
| fn | 関数 | ストリーム内の各アイテムに適用する関数。 |
| タイプ | 説明 |
|---|---|
| なし |
この例では、ストリーム内の各アイテムの結果を出力する方法を示します。
var firstNames = new global.GlideQuery('sys_user')
.select('first_name')
.forEach(function (u) {
gs.debug(u.first_name);
});
出力:
*** Script: [DEBUG] survey
*** Script: [DEBUG] Lucius
*** Script: [DEBUG] Jimmie
*** Script: [DEBUG] Melinda
*** Script: [DEBUG] Jewel
*** Script: [DEBUG] Sean
*** Script: [DEBUG] Jacinto
*** Script: [DEBUG] Krystle
*** Script: [DEBUG] Billie
*** Script: [DEBUG] Christian
*** Script: [DEBUG] Naomi
...
Stream - fromArray(オブジェクト arr)
指定されたアレイから取得した値を含む Stream オブジェクトを返します。
| 名前 | タイプ | 説明 |
|---|---|---|
| arr | アレイ | ストリームの作成元となる値のアレイ。 |
| タイプ | 説明 |
|---|---|
| ストリーム | レコードなどのアイテムのストリームを操作するために使用されるオブジェクト。 |
この例では、値のアレイを含む Stream オブジェクトを作成する方法を示します。
var nameStream = Stream.fromArray(['Bob', 'Sue', 'Sam'])
.map(function (name) {
return name.toUpperCase();
})
.toArray(3);
gs.info(JSON.stringify(nameStream));
出力:
["BOB","SUE","SAM"]
Stream - limit(数字 count)
ストリームによって返される結果の数を制限します。
パフォーマンスを向上させるには、可能であれば GlideQuery クラスで limit() メソッドを使用します。「GlideQuery()」を参照してください。必要に応じて、このメソッドで Stream.flatMap() メソッドを使用して結果を制限します。
| 名前 | タイプ | 説明 |
|---|---|---|
| count | 数字 | 返されるレコードの数。 |
| タイプ | 説明 |
|---|---|
| ストリーム | レコードなどのアイテムのストリームを操作するために使用されるオブジェクト。 |
この例は、Stream.flatMap() メソッドから返される結果を制限する方法を示しています。
var records = new global.GlideQuery('sys_user')
.where('last_login', '>', '2015-12-31')
.select('first_name', 'last_name')
.flatMap(function (u) {
return new GlideQuery('task')
.where('closed_by', u.sys_id)
.select('closed_at', 'description')
.map(function (t) {
return {
first_name: u.first_name,
last_name: u.last_name,
description: t.description,
closed_at: t.closed_at
};
});
})
.limit(5)
.forEach(function (task){
gs.info(JSON.stringify(task, null, 2));
});
出力:
*** Script: {
"first_name": "System",
"last_name": "Administrator",
"description": null,
"closed_at": "2021-10-04 13:40:16"
}
*** Script: {
"first_name": "System",
"last_name": "Administrator",
"description": null,
"closed_at": "2021-10-04 13:40:22"
}
*** Script: {
"first_name": "System",
"last_name": "Administrator",
"description": null,
"closed_at": "2021-10-04 13:40:27"
}
*** Script: {
"first_name": "System",
"last_name": "Administrator",
"description": null,
"closed_at": "2021-10-04 13:40:31"
}
*** Script: {
"first_name": "System",
"last_name": "Administrator",
"description": null,
"closed_at": "2021-10-04 13:40:54"
}
Stream - map(関数 fn)
ストリーム内の各アイテムに関数を適用し、更新後の Stream オブジェクトを返します。
| 名前 | タイプ | 説明 |
|---|---|---|
| fn | 関数 | ストリーム内の各アイテムを入力として受け取るクエリーの結果に適用する関数。 |
| タイプ | 説明 |
|---|---|
| ストリーム | 関数を適用した後に更新されたレコードのストリームを含むオブジェクト。 |
この例では、ストリーム内の全アイテムに関数を適用する方法を示します。
var users = new global.GlideQuery('sys_user')
.whereNotNull('first_name')
.select('first_name')
.map(function (u) {
return u.first_name.toUpperCase();
})
.toArray(100);
gs.info(JSON.stringify(users));
出力:
[
"SURVEY",
"LUCIUS",
"JIMMIE",
"MELINDA",
"JEWEL",
"SEAN",
"JACINTO",
"KRYSTLE",
"BILLIE",
"CHRISTIAN",
...
]
Stream - reduce(関数 reducerFn, 任意 initialValue)
ストリーム内の各アイテムに対して reducer 関数を実行し、単一の出力値を生成します。
このメソッドは、ネイティブの JavaScript の reduce() メソッドに類似しています。詳細については、w3schools のドキュメントを参照してください。
| 名前 | タイプ | 説明 |
|---|---|---|
| reducerFn | 関数 | ストリーム内の各アイテムに適用して、ストリームを単一の値に減らす関数。この関数は次の 2 つの引数を取る必要があります。
|
| initialValue | 任意 | 初期値として関数に渡される値。 |
| タイプ | 説明 |
|---|---|
| 任意 | reducer 関数によって返されたすべてのアイテムの累計。 |
この例では、ユーザーテーブルから最も長い名前のレコードを返す方法を示しています。
var longestName = new global.GlideQuery('sys_user')
.whereNotNull('first_name')
.select('first_name')
.reduce(function (acc, cur) {
return cur.first_name.length > acc.length
? cur.first_name
: acc;
}, '');
gs.info(JSON.stringify(longestName));
出力:
"ATF_TestItilUser1"
Stream - some(関数 predicate)
述語関数 (単一の値を受け取って true または false を返す関数) を、ストリーム内の各アイテムに適用します。述語がストリーム内のいずれかのアイテムに対して true を返す場合、メソッドは true を返します。
| 名前 | タイプ | 説明 |
|---|---|---|
| predicate | 関数 | Stream オブジェクト内のアイテムに適用する述語関数。ブーリアン値を返す必要があります。 |
| タイプ | 説明 |
|---|---|
| ブーリアン | 述語関数がストリーム内のアイテムに対して true を返したかどうかを示すフラグ。 有効な値:
|
この例は、タスクテーブル内の説明が 1,000 文字を超えているかどうかを確認する方法を示しています。
var hasLongDescriptions = new global.GlideQuery('task')
.whereNotNull('description')
.select('description')
.some(function (t) {
return t.description.length > 1000;
});
gs.info(hasLongDescriptions);
出力:
false
Stream - toArray(数字 count)
ストリームから指定された数のアイテムを含むアレイを返します。
| 名前 | タイプ | 説明 |
|---|---|---|
| count | 数字 | ストリームがアレイ内で返すアイテムの最大数。 |
| タイプ | 説明 |
|---|---|
| アレイ | ストリームから返された、指定の数のアイテムを含むアレイ。 |
この例では、レコードのストリームを JavaScript アレイに変換する方法を示します。
var users = new global.GlideQuery('sys_user')
.limit(10)
.select('first_name', 'last_name')
.toArray(50);
gs.info(JSON.stringify(users));
出力:
[
{
"first_name":"Jewel",
"last_name":"Agresta",
"sys_id":"02826bf03710200044e0bfc8bcbe5d64"
},
{
"first_name":"Sean",
"last_name":"Bonnet",
"sys_id":"02826bf03710200044e0bfc8bcbe5d6d"
},
{
"first_name":"Jacinto",
"last_name":"Gawron",
"sys_id":"02826bf03710200044e0bfc8bcbe5d76"
},
{
"first_name":"Krystle",
"last_name":"Stika",
"sys_id":"02826bf03710200044e0bfc8bcbe5d7f"
},
{
"first_name":"Billie",
"last_name":"Cowley",
"sys_id":"02826bf03710200044e0bfc8bcbe5d88"
},
{
"first_name":"Christian",
"last_name":"Marnell",
"sys_id":"02826bf03710200044e0bfc8bcbe5d91"
}
]