data-policies について
ServiceNow 開発者向けに、テーブルやフィールドの定義とデータ整合性を保つポリシー規則を解説するガイドです。ES5 の例、スキーマ検索方法、関連する MCP ツールを紹介します。
主な機能
- 01テーブルとフィールド定義の管理
- 02辞書オーバーライドと選択肢の設定
- 03データポリシーとルールの作成
- 04フィールド検証とスキーマ検索
- 05関連する MCP ツールの紹介
活用シーン
- 01カスタムテーブルのフィールド設計
- 02レコードへの業務データ要件の適用
- 03テーブル項目やポリシー設定の確認
MCP 対応
辞書とデータポリシーの操作に使う ServiceNow MCP ツールとして、snow_query_table、snow_discover_table_fields、snow_execute_script を挙げています。フィールド定義の確認やデータポリシー検索の例もあります。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ serac-labs/ serac --skill data-policiesインストール後、Claude Code で/data-policiesを入力して読み込まれたか確認します。
詳細
ServiceNow のデータポリシーとディクショナリ
データポリシーはデータ整合性ルールを適用します。ディクショナリはスキーマとフィールドの動作を制御します。
アーキテクチャ
Dictionary (sys_dictionary)
├── Field Definition
│ ├── Type, Length, Default
│ └── Dependent Field
└── Dictionary Overrides (sys_dictionary_override)
Data Policy (sys_data_policy2)
└── Data Policy Rules (sys_data_policy_rule)
└── Condition-based field behaviors
主なテーブル
| テーブル | 用途 |
|---|---|
sys_dictionary | フィールド定義 |
sys_dictionary_override | スコープ付きの上書き |
sys_data_policy2 | データポリシー |
sys_data_policy_rule | ポリシールール |
sys_db_object | テーブル定義 |
ディクショナリの管理(ES5)
テーブルの作成
// Create custom table (ES5 ONLY!)
var table = new GlideRecord("sys_db_object")
table.initialize()
table.setValue("name", "u_custom_table")
table.setValue("label", "Custom Table")
table.setValue("super_class", "task") // Extends task
table.setValue("is_extendable", true)
table.setValue("create_access_controls", true)
table.setValue("live_feed_enabled", false)
table.insert()
フィールドの作成
// Create field on table (ES5 ONLY!)
var field = new GlideRecord("sys_dictionary")
field.initialize()
// Table and element
field.setValue("name", "u_custom_table")
field.setValue("element", "u_customer_name")
// Field properties
field.setValue("column_label", "Customer Name")
field.setValue("internal_type", "string")
field.setValue("max_length", 100)
field.setValue("mandatory", false)
field.setValue("read_only", false)
field.setValue("display", false)
field.setValue("active", true)
// Default value
field.setValue("default_value", "")
// Reference field specific
// field.setValue('reference', 'customer_account');
// field.setValue('reference_qual', 'active=true');
field.insert()
フィールドの種類
// Common field types
var FIELD_TYPES = {
STRING: "string",
INTEGER: "integer",
DECIMAL: "decimal",
BOOLEAN: "boolean",
GLIDE_DATE: "glide_date",
GLIDE_DATE_TIME: "glide_date_time",
REFERENCE: "reference",
CHOICE: "choice",
JOURNAL: "journal",
JOURNAL_INPUT: "journal_input",
HTML: "html",
URL: "url",
EMAIL: "email",
SCRIPT: "script",
CONDITIONS: "conditions",
}
// Create different field types (ES5 ONLY!)
function createField(tableName, fieldDef) {
var field = new GlideRecord("sys_dictionary")
field.initialize()
field.setValue("name", tableName)
field.setValue("element", fieldDef.name)
field.setValue("column_label", fieldDef.label)
field.setValue("internal_type", fieldDef.type)
if (fieldDef.maxLength) {
field.setValue("max_length", fieldDef.maxLength)
}
if (fieldDef.reference) {
field.setValue("reference", fieldDef.reference)
}
if (fieldDef.choices) {
field.setValue("choice", 1) // Has choices
}
return field.insert()
}
選択肢の作成
// Create choice list values (ES5 ONLY!)
function createChoices(tableName, fieldName, choices) {
for (var i = 0; i < choices.length; i++) {
var choice = new GlideRecord("sys_choice")
choice.initialize()
choice.setValue("name", tableName)
choice.setValue("element", fieldName)
choice.setValue("value", choices[i].value)
choice.setValue("label", choices[i].label)
choice.setValue("sequence", (i + 1) * 10)
choice.setValue("inactive", false)
choice.insert()
}
}
// Usage
createChoices("incident", "u_custom_status", [
{ value: "pending", label: "Pending Review" },
{ value: "approved", label: "Approved" },
{ value: "rejected", label: "Rejected" },
])
ディクショナリの上書き(ES5)
上書きの作成
// Create dictionary override for scoped app (ES5 ONLY!)
var override = new GlideRecord("sys_dictionary_override")
override.initialize()
// Reference the base field
override.setValue("base_table", "task")
override.setValue("base_element", "short_description")
// Target table
override.setValue("name", "u_custom_table")
// Override properties
override.setValue("column_label", "Request Summary")
override.setValue("mandatory", true)
override.setValue("read_only", false)
override.setValue("max_length", 200)
// Default value override
override.setValue("default_value", "")
override.insert()
データポリシー(ES5)
データポリシーの作成
// Create data policy (ES5 ONLY!)
var policy = new GlideRecord("sys_data_policy2")
policy.initialize()
policy.setValue("model_table", "incident")
policy.setValue("short_description", "Resolution Fields Required on Resolve")
policy.setValue("active", true)
// Conditions - when policy applies
policy.setValue("conditions", "state=6") // Resolved state
// Apply to forms
policy.setValue("apply_to_client", true)
policy.setValue("apply_to_import_sets", true)
policy.setValue("apply_to_soap", true)
// Reverse
policy.setValue("reverse_if_false", true)
var policySysId = policy.insert()
// Add policy rules
addDataPolicyRule(policySysId, "resolution_code", true, false, false)
addDataPolicyRule(policySysId, "close_notes", true, false, false)
ポリシールールの追加
// Add data policy rule (ES5 ONLY!)
function addDataPolicyRule(policySysId, fieldName, mandatory, readOnly, hidden) {
var rule = new GlideRecord("sys_data_policy_rule")
rule.initialize()
rule.setValue("sys_data_policy", policySysId)
rule.setValue("field", fieldName)
rule.setValue("mandatory", mandatory)
rule.setValue("read_only", readOnly)
rule.setValue("visible", !hidden)
return rule.insert()
}
複雑なデータポリシー
// Data policy with scripted condition (ES5 ONLY!)
var policy = new GlideRecord("sys_data_policy2")
policy.initialize()
policy.setValue("model_table", "change_request")
policy.setValue("short_description", "High Risk Change Requirements")
policy.setValue("active", true)
// Use scripted condition for complex logic
policy.setValue("use_as_condition", true)
policy.setValue(
"script",
"(function checkCondition(current) {\n" +
" // High risk changes require additional fields\n" +
' if (current.risk == "high") {\n' +
" return true;\n" +
" }\n" +
" \n" +
" // Also apply to changes affecting critical CIs\n" +
" if (current.cmdb_ci) {\n" +
" var ci = current.cmdb_ci.getRefRecord();\n" +
' if (ci.business_criticality == "1 - most critical") {\n' +
" return true;\n" +
" }\n" +
" }\n" +
" \n" +
" return false;\n" +
"})(current);",
)
var policySysId = policy.insert()
// Require additional documentation for high risk
addDataPolicyRule(policySysId, "implementation_plan", true, false, false)
addDataPolicyRule(policySysId, "backout_plan", true, false, false)
addDataPolicyRule(policySysId, "test_plan", true, false, false)
addDataPolicyRule(policySysId, "justification", true, false, false)
フィールドの検証(ES5)
ディクショナリ属性の検証
// Add validation to dictionary field (ES5 ONLY!)
var field = new GlideRecord("sys_dictionary")
if (field.get("name", "incident").get("element", "u_email")) {
// Add regex validation
field.setValue("attributes", "validate=email")
field.update()
}
// Common validation attributes
var VALIDATION_ATTRIBUTES = {
EMAIL: "validate=email",
PHONE: "validate=phone_number",
URL: "validate=url",
CUSTOM: "validate=script", // Uses script in Calculated Value
}
スクリプトによる検証
// Calculated field with validation (ES5 ONLY!)
// Set in Dictionary > Calculated Value
// Check phone format
;(function calculate() {
var phone = current.getValue("u_phone")
if (!phone) return ""
// Format validation
var phonePattern = /^\+?[1-9]\d{1,14}$/
if (!phonePattern.test(phone.replace(/[\s\-\(\)]/g, ""))) {
gs.addErrorMessage("Invalid phone number format")
return ""
}
return phone
})()
スキーマのクエリ(ES5)
テーブルのフィールドを取得
// Get all fields for a table (ES5 ONLY!)
function getTableFields(tableName) {
var fields = []
var dict = new GlideRecord("sys_dictionary")
dict.addQuery("name", tableName)
dict.addQuery("internal_type", "!=", "collection")
dict.addQuery("active", true)
dict.orderBy("element")
dict.query()
while (dict.next()) {
fields.push({
name: dict.getValue("element"),
label: dict.getValue("column_label"),
type: dict.getValue("internal_type"),
mandatory: dict.getValue("mandatory") === "true",
reference: dict.getValue("reference"),
maxLength: dict.getValue("max_length"),
})
}
return fields
}
フィールドの存在を確認
// Check if field exists on table (ES5 ONLY!)
function fieldExists(tableName, fieldName) {
var dict = new GlideRecord("sys_dictionary")
dict.addQuery("name", tableName)
dict.addQuery("element", fieldName)
dict.query()
return dict.hasNext()
}
MCP ツールの統合
利用可能なツール
| ツール | 用途 |
|---|---|
snow_query_table | ディクショナリとデータポリシーをクエリ |
snow_discover_table_fields | フィールド定義を取得 |
snow_execute_script | ディクショナリスクリプトをテスト |
ワークフローの例
// 1. Get table fields
await snow_discover_table_fields({
table_name: "incident",
})
// 2. Query data policies
await snow_query_table({
table: "sys_data_policy2",
query: "model_table=incident^active=true",
fields: "short_description,conditions,apply_to_client",
})
// 3. Check dictionary overrides
await snow_query_table({
table: "sys_dictionary_override",
query: "name=u_custom_table",
fields: "base_element,column_label,mandatory,read_only",
})
ベストプラクティス
- スキーマの計画 - 実装前に設計します
- フィールドの命名 - カスタムフィールドには u_ プレフィックスを使用します
- データ型 - 適切な型を使用します
- 必須フィールド - 本当に必要な場合にのみ設定します
- データポリシー - ビジネスルールを適用します
- パフォーマンス - 複雑な計算フィールドは避けます
- ドキュメント - カスタムスキーマを文書化します
- ES5 のみ - モダンな JavaScript 構文は使用しません
コメント
Markdown 対応