Data Policies & Dictionary for ServiceNow
Data Policies enforce data integrity rules. Dictionary controls schema and field behavior.
Architecture
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
Key Tables
Table Purpose
sys_dictionary
Field definitions
sys_dictionary_override
Scoped overrides
sys_data_policy2
Data policies
sys_data_policy_rule
Policy rules
sys_db_object
Table definitions
Dictionary Management (ES5)
Create Table
// 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
// 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()
Field Types
// 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 Choices
// 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" }, ])
Dictionary Overrides (ES5)
Create Override
// 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()
Data Policies (ES5)
Create Data Policy
// 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 Policy Rules
// 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() }
Complex Data Policy
// 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)
Field Validation (ES5)
Dictionary Attribute Validation
// 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 }
Script Validation
// 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 })()
Schema Queries (ES5)
Get Table Fields
// 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 Field Exists
// 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 Tool Integration
Available Tools
Tool Purpose
snow_query_table
Query dictionary
snow_discover_table_fields
Get field definitions
snow_execute_script_with_output
Test dictionary scripts
snow_find_artifact
Find data policies
Example Workflow
// 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", })
Best Practices
-
Schema Planning - Design before implementation
-
Field Naming - u_ prefix for custom fields
-
Data Types - Use appropriate types
-
Mandatory Fields - Only when truly required
-
Data Policies - Enforce business rules
-
Performance - Avoid complex calculated fields
-
Documentation - Document custom schema
-
ES5 Only - No modern JavaScript syntax