Information on _queryMatch

garyminnick
Tera Contributor

I am trying to understand exactly how _queryMatch works in the Lookup Rules.  There is very little information other than the start of the default scripts.

// _queryMatch function checks if the query returns 0, 1 or more than 1 CI.
// it returns:
//    null: if no CI found
//    ci record: if a unique CI was found
//    the first CI record found: if more than 1 CI was found and log a duplicate error message

If more than one CI is found it says it returns the first one.  But there is no indication if it filters out CI's that are retired or non-operational, or try to get the one with the latest discovery date.  And the default scripts do not take those into account in the GlideRecord queries.

 

I have in my notes that the Lookup Rules will return the CI with the latest created date, but I cannot recall if I saw that in some ServiceNow docs or one of their videos.  So, I am not sure if the _queryMatch does anything with that.  Any help will be appreciated.  I will most likely just add those filters to the GlideRecord query so I can know what I am getting.  But, if I do that, what is the purpose of _queryMatch?

1 ACCEPTED SOLUTION

Ajay_Chavan
Kilo Sage

Core Behavior:

The _queryMatch function returns "the first CI record found" when multiple CIs match - it does NOT apply any intelligent filtering for operational status, discovery dates, or creation dates by default.

 

// Simple CI Lookup Rule Example - Hostname matching with proper filtering

(function process(rule, sourceValue, sourcePayload) {
    var sourceField = {};
    sourceField[rule.source_field] = sourceValue;
    
    // Query for CI by hostname
    var cmdbci = new GlideRecord("cmdb_ci_server");
    cmdbci.addQuery("host_name", sourceValue);
    
    // ADD YOUR FILTERS (what _queryMatch doesn't do)
    cmdbci.addQuery('operational_status', '1');        // Operational only
    cmdbci.addQuery('install_status', '!=', '7');      // Not retired
    cmdbci.addQuery('duplicate_of', '');               // Not a duplicate
    
    // Order by latest discovery date
    cmdbci.orderByDesc('last_discovered');
    
    cmdbci.query();
    
    // Use _queryMatch for logging and duplicate handling
    cmdbci = _queryMatch(cmdbci, rule, sourceField);
    
    if (cmdbci) {
        return cmdbci.getUniqueValue();
    }
    
    return null;
    
})(rule, sourceValue, sourcePayload);
Glad I could help! If this solved your issue, please mark it as Helpful and Accept as Solution so others can benefit too.*****Chavan A.P. | Technical Architect | Certified Professional*****

View solution in original post

4 REPLIES 4

Ajay_Chavan
Kilo Sage

Core Behavior:

The _queryMatch function returns "the first CI record found" when multiple CIs match - it does NOT apply any intelligent filtering for operational status, discovery dates, or creation dates by default.

 

// Simple CI Lookup Rule Example - Hostname matching with proper filtering

(function process(rule, sourceValue, sourcePayload) {
    var sourceField = {};
    sourceField[rule.source_field] = sourceValue;
    
    // Query for CI by hostname
    var cmdbci = new GlideRecord("cmdb_ci_server");
    cmdbci.addQuery("host_name", sourceValue);
    
    // ADD YOUR FILTERS (what _queryMatch doesn't do)
    cmdbci.addQuery('operational_status', '1');        // Operational only
    cmdbci.addQuery('install_status', '!=', '7');      // Not retired
    cmdbci.addQuery('duplicate_of', '');               // Not a duplicate
    
    // Order by latest discovery date
    cmdbci.orderByDesc('last_discovered');
    
    cmdbci.query();
    
    // Use _queryMatch for logging and duplicate handling
    cmdbci = _queryMatch(cmdbci, rule, sourceField);
    
    if (cmdbci) {
        return cmdbci.getUniqueValue();
    }
    
    return null;
    
})(rule, sourceValue, sourcePayload);
Glad I could help! If this solved your issue, please mark it as Helpful and Accept as Solution so others can benefit too.*****Chavan A.P. | Technical Architect | Certified Professional*****

garyminnick
Tera Contributor

Thanks for the information.  I typically do what you posted above just to be sure.  However, it just bugged me not knowing exactly what it was meant for.  Thanks for clarifying.

Ajay_Chavan
Kilo Sage

Glad I could help! If this solved your issue, please mark it as Helpful and Accept as Solution so others can benefit too.

 

Chavan A.P. Technical Architect | Certified Professional

Glad I could help! If this solved your issue, please mark it as Helpful and Accept as Solution so others can benefit too.*****Chavan A.P. | Technical Architect | Certified Professional*****

garyminnick
Tera Contributor

 

So, I ran into another issue that now makes me question if _queryMatch does take into account Retired records or if there is something else going on.

 

I removed all my query lines for operational_status, install_status and duplicate_of (see code below)

I reapplied the lookup rules to a specific Discovered Item where it's CI record is Operational Status = Retired and Install Status = Retired.  I would think the Lookup Rule would pick the Retired CI now that I am not filtering them out.  However, what happened is the Lookup Rules failed to match and it was matched by IRE to the Retired CI.  It also set the Op Status to Operational.

 

Next, I created a matrix to go through all the different Ops Status and Install Status options.  After a while I noticed a pattern and stopped because it was taking a long time.  I made it through all Operational Status options with Install Status of Installed, Absent, In Maintenance and In Stock before stopping.  All were same outcome as below where only Operational Status = Retired and/or Install Status = Retired caused the CI Lookup rules to not match and it went to the IRE even though I was not filtering on those in my script.  Operational Status = Non-Operational did not seem to have any effect as long as Install Status was not retired.  Meaning Operational Status = Non-Operational and Install Status = Absent did Match by CI Lookup rules (also in matrix below).

 

 

Operational StatusInstall StatusOutcome
OperationalInstalledMatched by CI Lookup rules
Non-OperationalInstalledMatched by CI Lookup rules
Repair in ProgressInstalledMatched by CI Lookup rules
DR StandbyInstalledMatched by CI Lookup rules
ReadyInstalledMatched by CI Lookup rules
RetiredInstalledMatched by IRE
OperationalAbsentMatched by CI Lookup rules
Non-OperationalAbsentMatched by CI Lookup rules
Repair in ProgressAbsentMatched by CI Lookup rules
DR StandbyAbsentMatched by CI Lookup rules
ReadyAbsentMatched by CI Lookup rules
RetiredAbsentMatched by IRE
OperationalRetiredMatched by IRE
ReadyRetiredMatched by IRE

 

So, it seems having the queries for retired and non-op in the script does not matter. Either there is some setting I am not aware of, or _queryMatch does take into account the Op Status and Install Status.

 

// _queryMatch function checks if the query returns 0, 1 or more than 1 CI.
// it returns:
//    null: if no CI found
//    ci record: if a unique CI was found
//    the first CI record found: if more than 1 CI was found and log a duplicate error message
//    To avoid specific CI classes ,add the class names, comma separated, to the property sn_sec_cmn.ignoreCIClass

(function process(rule, sourceValue, sourcePayload) {
	var sourceField = {};
	var ignore = global.SecProperty.getProperty("sn_sec_cmn.ignoreCIClass", "");
	sourceField[rule.source_field] = sourceValue;
	
	var cmdbci = new GlideRecord("cmdb_ci");
	cmdbci.addQuery("fqdn", sourceValue);

        // Order by latest discovered date
        cmdbci.orderByDesc('last_discovered');

	if (!gs.nil(ignore))
        cmdbci.addQuery('sys_class_name','NOT IN', ignore);
	cmdbci.query();

	cmdbci = _queryMatch(cmdbci, rule, sourceField);
	
	if (cmdbci)
		return cmdbci.getUniqueValue();
		
	return null;
})(rule, sourceValue, sourcePayload);