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