/** * Get records with duplicate values in multiple fields, and return a list of the records' * counts and the dupe fields' values. * * @param {string} tableName - The table to check for duplicates. Must be a string. * * @param {string|string[]} arrDupeFields - The fields to check for duplicates. * Must be a string or an array of strings. * * @param {string|string[]} [nonBlankFields=[]] - This optional parameter, if specified, will * be an array of strings consisting of the names of the fields which should not be allowed * to be blank when checking for duplicates. * To put it another way, if any of the fields specified in the `nonBlankFields` array are * blank, then the record should not be considered a duplicate. * Note that the fields specified in nonBlankFields do NOT need to also be specified in * arrDupeFields. * * @param {boolean} [getDupeSysIds=false] - If true, the sys_ids of the records with the * duplicate values will be included in the returned object. If false, they will not be * included. * This may have a performance impact, as it requires an additional query for each * duplicate combination, so use with caution. * Default is false. * * @returns {{dupeCount: (*|number), fields: {}}[]} - An array of objects, each object * representing a confluence of duplicate values in the specified fields - a specific * combination of field values - and the number of records that have that combination of * those values in the specified fields. */ function getMultiFieldDupes(tableName, arrDupeFields, nonBlankFields, getDupeSysIds) { var gaMyTableDuplicate, grDupe, iNonBlankField, iDupeField, objDupeRecord; var arrDupeRecords = []; var dupeCount = 0; /***** INPUT VALIDATION *****/ getDupeSysIds = (typeof getDupeSysIds === 'boolean') ? getDupeSysIds : false; if (typeof tableName !== 'string' || !tableName) { throw new Error( 'getMultiFieldDupes(): tableName must be a string consisting of a valid ' + 'table name in the ServiceNow database.' ); } if ( //If arrDupeFields is not an array or a string, or if it's an array but it's empty typeof arrDupeFields === 'undefined' || !arrDupeFields || (!Array.isArray(arrDupeFields) && typeof arrDupeFields !== 'string') || !arrDupeFields.length ) { throw new Error( 'getMultiFieldDupes(): arrDupeFields must be a string with a single ' + 'field name, or an array of strings - each string representing a ' + 'field name in the ' + tableName + ' table.' ); } //If arrDupeFields is a string, convert it to an array. if (typeof arrDupeFields === 'string') { arrDupeFields = arrDupeFields.split(','); } //If nonBlankFields is undefined, null, or an empty string, set it to an empty array. //If it's a string, convert it to an array. if (typeof nonBlankFields === 'undefined' || !nonBlankFields) { nonBlankFields = []; } else if (typeof nonBlankFields === 'string') { //Splitting just in case the input data is a comma-separated string - which it // shouldn't be, but I don't trust anyone who calls this code. They seem sus. nonBlankFields = nonBlankFields.split(','); } else if (!Array.isArray(nonBlankFields)) { //If it's not a string or an array or undefined, throw an error because wth am I s'posed to do with that throw new Error( 'getMultiFieldDupes(): nonBlankFields must be a string with a single ' + 'field name, or an array of strings - each string representing a ' + 'field name in the ' + tableName + ' table.' ); } /***** ACTUALLY DOING THE THING *****/ gaMyTableDuplicate = new GlideAggregate(tableName); gaMyTableDuplicate.addAggregate('COUNT'); //Group by each field in the arrDupeFields array for ( iDupeField = 0; iDupeField < arrDupeFields.length; iDupeField++ ) { gaMyTableDuplicate.groupBy(arrDupeFields[iDupeField]); } //If any nonBlankFields were specified, add a query to exclude records where // any of those fields are blank. for ( iNonBlankField = 0; iNonBlankField < nonBlankFields.length; iNonBlankField++ ) { gaMyTableDuplicate.addNotNullQuery(nonBlankFields[iNonBlankField]); } //Only show records with more than one match (duplicates) gaMyTableDuplicate.addHaving('COUNT', '>', 1); gaMyTableDuplicate.query(); while (gaMyTableDuplicate.next()) { dupeCount = gaMyTableDuplicate.getAggregate('COUNT'); //Populate the arrDupeRecords array with some info about the records that have duplicates objDupeRecord = { "dupeCount": dupeCount, "fields": {} }; //For each field in the arrDupeFields array, add that field's value to // the objDupeRecord.fields object. for ( iDupeField = 0; iDupeField < arrDupeFields.length; iDupeField++ ) { objDupeRecord.fields[arrDupeFields[iDupeField]] = gaMyTableDuplicate.getValue(arrDupeFields[iDupeField]); } if (getDupeSysIds) { objDupeRecord.dupe_sys_ids = []; //Add the sys_ids of all the records that have this combination of dupe fields in objDupeRecord.dupe_sys_ids: grDupe = new GlideRecord(tableName); for ( iDupeField = 0; iDupeField < arrDupeFields.length; iDupeField++ ) { grDupe.addQuery(arrDupeFields[iDupeField], objDupeRecord.fields[arrDupeFields[iDupeField]]); } grDupe.query(); while (grDupe.next()) { objDupeRecord.dupe_sys_ids.push(grDupe.getUniqueValue()); } } arrDupeRecords.push(objDupeRecord); } return arrDupeRecords; }
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter