<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Service-Now on SNow adventures</title>
    <link>https://www.snow-adventures.com/tags/service-now/</link>
    <description>Recent content in Service-Now on SNow adventures</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>© Samuel Meylan - 2020</copyright>
    <lastBuildDate>Thu, 05 Jun 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://www.snow-adventures.com/tags/service-now/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Toggle two fields disabled state with a UI policy</title>
      <link>https://www.snow-adventures.com/posts/toggle-two-fields-disabled-state-with-a-ui-policy/</link>
      <pubDate>Thu, 05 Jun 2025 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/toggle-two-fields-disabled-state-with-a-ui-policy/</guid>
      <description>This article explains how to toggle two fields with a UI policy</description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<p>This article explains how to implement a UI policy to toggle the disabled/mandatory states of two fields based on their values.</p>
<p>The goal is to control the accessibility and mandatory setting of two fields, based on their values, such as if the first field is set, then the other field becomes disabled and vice-versa.</p>
<p>There could be various way to implement this, and this article proposes to do it with a UI policy.</p>
<p>For instance, let&rsquo;s say we have two fields: Company and Person. The user must populate either one of these fields, as shown in this recording:</p>
<video autoplay loop muted playsinline style="width: auto;">
  <source src="/img/2025-06-05-Toggle-two-fields-disabled-state-with-a-UI-policy_demo.webm" type="video/webm">
  Your browser does not support the video tag.
</video>
<h2 id="implementation">Implementation</h2>
<p>To achieve this, we can create a <strong>UI policy</strong> named &ldquo;Toggle disabled state of Company and Person&rdquo; on the table.</p>
<h3 id="conditions">Conditions</h3>
<p>In the conditions, you need to checks whether either field contains any value, by using &ldquo;Company Is Anything or Person is Anything&rdquo; (<code>companyANYTHING^ORpersonANYTHING^EQ</code>).</p>
<figure>
    <img loading="lazy" src="/img/2025-06-05-Toggle-two-fields-disabled-state-with-a-UI-policy_conditions.png"/> <figcaption>
            Conditions on the fields
        </figcaption>
</figure>

<h3 id="scripts">Scripts</h3>
<p>Then, in the Script tab, set &ldquo;Run scripts&rdquo; and enter the two scripts like in the examples below.</p>
<h4 id="when-the-condition-is-true">When the Condition is True</h4>
<p>The condition evaluates to true when at least one of the fields (&ldquo;company&rdquo; or &ldquo;person&rdquo;) contains a value.</p>
<p>The script then disables the field that does not have a value while leaving the field with a value enabled.</p>
<p>This ensures that users input data into only one of these fields.</p>
<p>If by any chance both fields contain values, neither of them is disabled, allowing the user to retain or modify the existing data in both fields.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">onCondition</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">		The condition is true when at least one of the two fields has a value set.
</span></span></span><span class="line"><span class="cl"><span class="cm">		In this case, we disable the other field, except for the case where both fields are set.
</span></span></span><span class="line"><span class="cl"><span class="cm">	*/</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// Names of the fields
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">let</span> <span class="nx">companyField</span> <span class="o">=</span> <span class="s2">&#34;company&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">personField</span> <span class="o">=</span> <span class="s2">&#34;person&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// Get the value of the fields
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">let</span> <span class="nx">companyValue</span> <span class="o">=</span> <span class="nx">g_form</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="nx">companyField</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">personValue</span> <span class="o">=</span> <span class="nx">g_form</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="nx">personField</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="c1">// If both values are set (e.g., set from the list), return as we don&#39;t want to disable any of them.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">if</span> <span class="p">(</span><span class="nx">companyValue</span> <span class="o">&amp;&amp;</span> <span class="nx">personValue</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="c1">// If the company is set, disable the person field
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">if</span> <span class="p">(</span><span class="nx">companyValue</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setMandatory</span><span class="p">(</span><span class="nx">personField</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setDisabled</span><span class="p">(</span><span class="nx">personField</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// If the person is set, disable the company field
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">if</span> <span class="p">(</span><span class="nx">personValue</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setMandatory</span><span class="p">(</span><span class="nx">companyField</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setDisabled</span><span class="p">(</span><span class="nx">companyField</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h4 id="when-the-condition-is-false">When the Condition is False</h4>
<p>The condition becomes false when neither the &ldquo;company&rdquo; nor &ldquo;person&rdquo; fields have values set.</p>
<p>The script then enables both fields, making them available for user to input data, and sets them as mandatory.</p>
<p>The user is required to populate at least one of these fields for the form.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">onCondition</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">		The condition is false when both fields are not set.
</span></span></span><span class="line"><span class="cl"><span class="cm">		In this case, we enable both fields as they are open for input.
</span></span></span><span class="line"><span class="cl"><span class="cm">	*/</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// Names of the fields
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">let</span> <span class="nx">companyField</span> <span class="o">=</span> <span class="s2">&#34;company&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">personField</span> <span class="o">=</span> <span class="s2">&#34;person&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// Get the value of the fields
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">let</span> <span class="nx">companyValue</span> <span class="o">=</span> <span class="nx">g_form</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="nx">companyField</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">personValue</span> <span class="o">=</span> <span class="nx">g_form</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="nx">personField</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="c1">// If the company field is not set, enable the person field
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">companyValue</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setMandatory</span><span class="p">(</span><span class="nx">personField</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setDisabled</span><span class="p">(</span><span class="nx">personField</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// If the person field is not set, enable the company field
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">personValue</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setMandatory</span><span class="p">(</span><span class="nx">companyField</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">g_form</span><span class="p">.</span><span class="nx">setDisabled</span><span class="p">(</span><span class="nx">companyField</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="what-does-the-isanything-operator-do-">What does the ISANYTHING operator do ?</h2>
<p>Now you are maybe wondering what is the ISANYTHING operator that we are using the UI policy.</p>
<p>According to ServiceNow documentation<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, it means that it matches on the following values: any value, empty, null.</p>
<p>Also in the KB article KB0815207<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, it says:</p>
<blockquote>
<p>By design, the &ldquo;is anything&rdquo; filter operator always evaluates to true whether a field is empty or not.&quot;</p>
</blockquote>
<h3 id="but-is-this-really-true-">But is this really true ?</h3>
<p>The explanations above were all I could find in the documentation (admittedly I didn&rsquo;t look much more). But then, if it is always true, why do we need a script for the false condition ?</p>
<p>To be sure, I made a test by displaying a message in each script, so to know which one is executed when, like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Test execution 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">let</span> <span class="nx">msg</span> <span class="o">=</span> <span class="sb">`condition TRUE\ncompanyField=</span><span class="si">${</span><span class="nx">companyValue</span><span class="si">}</span><span class="sb"> (</span><span class="si">${</span><span class="nx">companyValue</span><span class="o">==</span><span class="kc">null</span><span class="si">}</span><span class="sb">/</span><span class="si">${</span><span class="nx">companyValue</span><span class="o">==</span><span class="s2">&#34;&#34;</span><span class="si">}</span><span class="sb">)\npersonValue=</span><span class="si">${</span><span class="nx">personValue</span><span class="si">}</span><span class="sb"> (</span><span class="si">${</span><span class="nx">personValue</span><span class="o">==</span><span class="kc">null</span><span class="si">}</span><span class="sb">/</span><span class="si">${</span><span class="nx">personValue</span><span class="o">==</span><span class="s2">&#34;&#34;</span><span class="si">}</span><span class="sb">)`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">alert</span><span class="p">(</span><span class="nx">msg</span><span class="p">);</span>
</span></span></code></pre></div><p>You can see the result here:</p>
<video autoplay loop muted playsinline style="width: auto;">
  <source src="/img/2025-06-05-Toggle-two-fields-disabled-state-with-a-UI-policy_demo_message.webm" type="video/webm">
  Your browser does not support the video tag.
</video>
<p>So we can see that:</p>
<ul>
<li>when loading the empty form, it evaluates to false</li>
<li>when entering a value in one of the field, it evaluates to true</li>
<li>when emptying the field, it evaluates to false</li>
</ul>
<p>So we can observe that it doesn&rsquo;t really behave like it is suggested in the documentation.</p>
<p>But fortunately we can circumvent this discrepancies by using both the true and false script and achieve what we aimed for.</p>
<p>Despite of having two scripts, the UI policy solution is in my opinion more elegant than using Client Script. Using Client Script would require to have a script for each field and duplicate the code in different places. The UI policy allows to keep everything tidy in one place.</p>
<hr>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.servicenow.com/docs/bundle/yokohama-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html">Operators available for filters and queries</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://support.servicenow.com/kb?id=kb_article_view&amp;sysparm_article=KB0815207">UI Policy with &lsquo;is anything &rsquo; does not work. - Support and Troubleshooting - KB0815207</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>jsonPath in ServiceNow with GlideJsonPath</title>
      <link>https://www.snow-adventures.com/posts/jsonpath-in-servicenow-with-glidejsonpath/</link>
      <pubDate>Tue, 18 Feb 2025 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/jsonpath-in-servicenow-with-glidejsonpath/</guid>
      <description>This article explain how the JsonPath is supported in ServiceNow and how to use it with GlideJsonPath </description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<p>Since the Vancouver release, there is a new API <code>GlideJsonPath</code><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> that allows to query a JSON string with <em>jsonPath</em><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<p>The <em>jsonPath</em> can be viewed as the JSON equivalent of the XPath for XML. It allows to perform queries like <code>$.library.bools.*.title</code> for example. <em>Jsonpath</em> is offically a RFC since february 2024<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>I suspect the under the hood, it use the implementation JsonPath<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<h1 id="usage-of-the--glidejsonpath">Usage of the  <code>GlideJsonPath</code></h1>
<p>The official documentation<sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> is very succint and there is a couple of extra information that can help:</p>
<ul>
<li>the <code>GlideJsonPath</code> expect a <em>String</em>, not an object as parameter</li>
<li>the <code>read</code> function seems to return an <em>array</em> of <em>JavaObject</em>, which are not the same as the javascript objects. It might need some kind of converstion before being able to use it.</li>
</ul>
<p>To ease the usage, I suggest to use a function like this one, that accept an Object as parameter and return also a <strong>javascript</strong> Object:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">	@name executeJSONpath
</span></span></span><span class="line"><span class="cl"><span class="cm">	@description execute the JSON path on the given object and return the result 
</span></span></span><span class="line"><span class="cl"><span class="cm">	@param {Object} [obj] - Object on which to execute the json path
</span></span></span><span class="line"><span class="cl"><span class="cm">	@param {String} [jsonPath] - Json path to use for the query
</span></span></span><span class="line"><span class="cl"><span class="cm">	@return {Object} Object after applying the jsonPath read
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">executeJSONpath</span> <span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">path</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Convert the object to a JSON string
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">var</span> <span class="nx">jsonString</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// call and retrieve the result from GlideJsonPath
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">var</span> <span class="nx">gjp</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideJsonPath</span><span class="p">(</span><span class="nx">jsonString</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">gjpResult</span> <span class="o">=</span> <span class="nx">gjp</span><span class="p">.</span><span class="nx">read</span><span class="p">(</span><span class="nx">path</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">gjpResult</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">exception</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error in function &#39;executeJSONpath&#39; : &#34;</span> <span class="o">+</span> <span class="nx">exception</span> <span class="o">+</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">exception</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="json-path-syntax">JSON path syntax</h2>
<p>The JSON path syntax can be summarized as follow:</p>
<h2 id="dot-notation-or-bracket-notation">dot-notation or bracket-notation</h2>
<p>the JsonPath can use either a dot-notation, like <code>$.store.book[0].title</code> or a bracker-notation <code>$['store']['book'][0]['title']</code></p>
<p>It can also use a mix of both, like this example: <code>$['store']['book'][0].title</code></p>
<p>Also in the bracket notation, it is possibe to specify mutliple attribute to retrieve, for example: `$[&lsquo;store&rsquo;][&lsquo;book&rsquo;][0].[&ldquo;title&rdquo;, &ldquo;author&rdquo;]</p>
<h2 id="elements">Elements</h2>
<p>The JsonPath can use the following elements <sup id="fnref1:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup><sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup><sup id="fnref1:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>:</p>
<ul>
<li><code>$</code>: The root element to query. This starts all path expressions.</li>
<li><code>@</code>: The current node being processed by a filter predicate.</li>
<li><code>*</code>: Wildcard. Available anywhere a name or numeric are required.</li>
<li><code>..</code>: Deep scan. Available anywhere a name is required.</li>
<li><code>.&lt;name&gt;</code>: Dot-notated child</li>
<li><code>['&lt;name&gt;' (, '&lt;name&gt;')]</code>: Bracket-notated child or children</li>
<li><code>[&lt;number&gt; (, &lt;number&gt;)]</code>: Array index or indexes</li>
<li><code>[start:end]</code>: Array slice operator</li>
<li><code>[?(&lt;expression&gt;)]</code>: Filter expression. Expression must evaluate to a boolean value.</li>
</ul>
<h2 id="functions">Functions</h2>
<p>The specification gives several functions (<code>min()</code>, <code>max()</code>, &hellip;), but unfortunately it seems thay are not supported by the ServiceNow implementation.</p>
<h2 id="operators">Operators</h2>
<p>For use in the expression, we can use the &ldquo;classic&rdquo; operator like &ldquo;==&rdquo;, &ldquo;!=&rdquo;, &ldquo;&gt;&rdquo;, &ldquo;=&gt;&rdquo;, etc. It also supports:</p>
<ul>
<li><code>=~</code>: left matches regular expression [?(@.name =~ /foo.*?/i)]</li>
<li><code>in</code>: left exists in right [?(@.size in [&lsquo;S&rsquo;, &lsquo;M&rsquo;])]</li>
<li><code>nin</code>: left does not exists in right</li>
<li><code>subsetof</code>: left is a subset of right [?(@.sizes subsetof [&lsquo;S&rsquo;, &lsquo;M&rsquo;, &lsquo;L&rsquo;])]</li>
<li><code>anyof</code>: left has an intersection with right [?(@.sizes anyof [&lsquo;M&rsquo;, &lsquo;L&rsquo;])]</li>
<li><code>noneof</code>: left has no intersection with right [?(@.sizes noneof [&lsquo;M&rsquo;, &lsquo;L&rsquo;])]</li>
<li><code>size</code>: size of left (array or string) should match right</li>
<li><code>empty</code>: left (array or string) should be empty</li>
</ul>
<h2 id="limitations">Limitations</h2>
<ul>
<li><strong>functions</strong>: functions are not supported, as stated above</li>
<li><strong>unique values</strong>: There is not way to ask for unique values: there can be duplicated entries (for example when listing all categories)</li>
</ul>
<h1 id="example-of-json-path">Example of JSON path</h1>
<p>This table show the result of various jsonPath from the GitHub JsonPath documentation<sup id="fnref2:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<p>When creating a new jsonPath, you can use this online evaluator<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> to test it</p>
<table>
  <thead>
      <tr>
          <th>Description</th>
          <th>JsonPath</th>
          <th>Result</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>The authors of all books</td>
          <td><code>$.store.book[*].author</code></td>
          <td>[</br> &ldquo;Nigel Rees&rdquo;,</br> &ldquo;Evelyn Waugh&rdquo;,</br> &ldquo;Herman Melville&rdquo;,</br> &ldquo;J. R. R. Tolkien&rdquo;</br>]</td>
      </tr>
      <tr>
          <td>The authors and category of all books</td>
          <td><code>$.store.book[*].[&lsquo;author&rsquo;,&rsquo;title&rsquo;]</code></td>
          <td>[</br> {</br>  &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;</br> },</br> {</br>  &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;</br> },</br> {</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;</br> },</br> {</br>  &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;</br> }</br>]</td>
      </tr>
      <tr>
          <td>Title of first book, mixing dot and bracket</td>
          <td><code>$[&lsquo;store&rsquo;][&lsquo;book&rsquo;][0].title</code></td>
          <td>[</br> &ldquo;Sayings of the Century&rdquo;</br>]</td>
      </tr>
      <tr>
          <td>All authors</td>
          <td><code>$..author</code></td>
          <td>[</br> &ldquo;Nigel Rees&rdquo;,</br> &ldquo;Evelyn Waugh&rdquo;,</br> &ldquo;Herman Melville&rdquo;,</br> &ldquo;J. R. R. Tolkien&rdquo;</br>]</td>
      </tr>
      <tr>
          <td>All things, both books and bicycles</td>
          <td><code>$.store.*</code></td>
          <td>[</br> [</br>  {</br>   &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>   &ldquo;price&rdquo;: 8.95</br>  },</br>  {</br>   &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;,</br>   &ldquo;price&rdquo;: 12.99</br>  },</br>  {</br>   &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>   &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>   &ldquo;price&rdquo;: 8.99</br>  },</br>  {</br>   &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;,</br>   &ldquo;isbn&rdquo;: &ldquo;0-395-19395-8&rdquo;,</br>   &ldquo;price&rdquo;: 22.99</br>  }</br> ],</br> {</br>  &ldquo;color&rdquo;: &ldquo;red&rdquo;,</br>  &ldquo;price&rdquo;: 19.95</br> }</br>]</td>
      </tr>
      <tr>
          <td>The price of everything</td>
          <td><code>$.store..price</code></td>
          <td>[</br> 8.95,</br> 12.99,</br> 8.99,</br> 22.99,</br> 19.95</br>]</td>
      </tr>
      <tr>
          <td>The third book</td>
          <td><code>$..book[2]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>The second to last book</td>
          <td><code>$..book[-2]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>The first two books</td>
          <td><code>$..book[0,1]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>  &ldquo;price&rdquo;: 8.95</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;,</br>  &ldquo;price&rdquo;: 12.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>All books from index 0 (inclusive) until index 2 (exclusive)</td>
          <td><code>$..book[:2]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>  &ldquo;price&rdquo;: 8.95</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;,</br>  &ldquo;price&rdquo;: 12.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>All books from index 1 (inclusive) until index 2 (exclusive)</td>
          <td><code>$..book[1:2]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;,</br>  &ldquo;price&rdquo;: 12.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>Last two books</td>
          <td><code>$..book[-2:]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-395-19395-8&rdquo;,</br>  &ldquo;price&rdquo;: 22.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>All books from index 2 (inclusive) to last</td>
          <td><code>$..book[2:]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-395-19395-8&rdquo;,</br>  &ldquo;price&rdquo;: 22.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>All books with an ISBN number</td>
          <td><code>$..book[?(@.isbn)]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-395-19395-8&rdquo;,</br>  &ldquo;price&rdquo;: 22.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>All books in store cheaper than 10</td>
          <td><code>$.store.book[?(@.price &lt; 10)]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>  &ldquo;price&rdquo;: 8.95</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>All books in store that are not &rsquo;expensive&rsquo;</td>
          <td><code>$..book[?(@.price &lt;= $[&rsquo;expensive&rsquo;])]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>  &ldquo;price&rdquo;: 8.95</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> }</br>]</td>
      </tr>
      <tr>
          <td>All books matching regex (ignore case)</td>
          <td><code>$..book[?(@.author =~ /.*REES/i)]</code></td>
          <td>[</br> {</br>  &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>  &ldquo;price&rdquo;: 8.95</br> }</br>]</td>
      </tr>
      <tr>
          <td>Give me everything</td>
          <td><code>$..*</code></td>
          <td>[</br> {</br>  &ldquo;book&rdquo;: [</br>   {</br>    &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>    &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>    &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>    &ldquo;price&rdquo;: 8.95</br>   },</br>   {</br>    &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>    &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>    &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;,</br>    &ldquo;price&rdquo;: 12.99</br>   },</br>   {</br>    &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>    &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>    &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>    &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>    &ldquo;price&rdquo;: 8.99</br>   },</br>   {</br>    &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>    &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>    &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;,</br>    &ldquo;isbn&rdquo;: &ldquo;0-395-19395-8&rdquo;,</br>    &ldquo;price&rdquo;: 22.99</br>   }</br>  ],</br>  &ldquo;bicycle&rdquo;: {</br>   &ldquo;color&rdquo;: &ldquo;red&rdquo;,</br>   &ldquo;price&rdquo;: 19.95</br>  }</br> },</br> 10,</br> [</br>  {</br>   &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>   &ldquo;price&rdquo;: 8.95</br>  },</br>  {</br>   &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;,</br>   &ldquo;price&rdquo;: 12.99</br>  },</br>  {</br>   &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>   &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>   &ldquo;price&rdquo;: 8.99</br>  },</br>  {</br>   &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>   &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>   &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;,</br>   &ldquo;isbn&rdquo;: &ldquo;0-395-19395-8&rdquo;,</br>   &ldquo;price&rdquo;: 22.99</br>  }</br> ],</br> {</br>  &ldquo;color&rdquo;: &ldquo;red&rdquo;,</br>  &ldquo;price&rdquo;: 19.95</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;reference&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Nigel Rees&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sayings of the Century&rdquo;,</br>  &ldquo;price&rdquo;: 8.95</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Evelyn Waugh&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Sword of Honour&rdquo;,</br>  &ldquo;price&rdquo;: 12.99</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;Herman Melville&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;Moby Dick&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-553-21311-3&rdquo;,</br>  &ldquo;price&rdquo;: 8.99</br> },</br> {</br>  &ldquo;category&rdquo;: &ldquo;fiction&rdquo;,</br>  &ldquo;author&rdquo;: &ldquo;J. R. R. Tolkien&rdquo;,</br>  &ldquo;title&rdquo;: &ldquo;The Lord of the Rings&rdquo;,</br>  &ldquo;isbn&rdquo;: &ldquo;0-395-19395-8&rdquo;,</br>  &ldquo;price&rdquo;: 22.99</br> },</br> &ldquo;reference&rdquo;,</br> &ldquo;Nigel Rees&rdquo;,</br> &ldquo;Sayings of the Century&rdquo;,</br> 8.95,</br> &ldquo;fiction&rdquo;,</br> &ldquo;Evelyn Waugh&rdquo;,</br> &ldquo;Sword of Honour&rdquo;,</br> 12.99,</br> &ldquo;fiction&rdquo;,</br> &ldquo;Herman Melville&rdquo;,</br> &ldquo;Moby Dick&rdquo;,</br> &ldquo;0-553-21311-3&rdquo;,</br> 8.99,</br> &ldquo;fiction&rdquo;,</br> &ldquo;J. R. R. Tolkien&rdquo;,</br> &ldquo;The Lord of the Rings&rdquo;,</br> &ldquo;0-395-19395-8&rdquo;,</br> 22.99,</br> &ldquo;red&rdquo;,</br> 19.95</br>]</td>
      </tr>
  </tbody>
</table>
<h2 id="sample-json">Sample JSON</h2>
<p>Here is the sample JSON used for the tests:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;store&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;book&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="s2">&#34;reference&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;author&#34;</span><span class="p">:</span> <span class="s2">&#34;Nigel Rees&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Sayings of the Century&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;price&#34;</span><span class="p">:</span> <span class="mf">8.95</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="s2">&#34;fiction&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;author&#34;</span><span class="p">:</span> <span class="s2">&#34;Evelyn Waugh&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Sword of Honour&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;price&#34;</span><span class="p">:</span> <span class="mf">12.99</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="s2">&#34;fiction&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;author&#34;</span><span class="p">:</span> <span class="s2">&#34;Herman Melville&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Moby Dick&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;isbn&#34;</span><span class="p">:</span> <span class="s2">&#34;0-553-21311-3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;price&#34;</span><span class="p">:</span> <span class="mf">8.99</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="s2">&#34;fiction&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;author&#34;</span><span class="p">:</span> <span class="s2">&#34;J. R. R. Tolkien&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;The Lord of the Rings&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;isbn&#34;</span><span class="p">:</span> <span class="s2">&#34;0-395-19395-8&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;price&#34;</span><span class="p">:</span> <span class="mf">22.99</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;bicycle&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;color&#34;</span><span class="p">:</span> <span class="s2">&#34;red&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;price&#34;</span><span class="p">:</span> <span class="mf">19.95</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;expensive&#34;</span><span class="p">:</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><hr>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://developer.servicenow.com/dev.do#!/reference/api/washingtondc/server_legacy/GlideJsonPathAPI#GlideJsonPath-GlideJsonPath_S?navFilter=jsonpath">GlideJsonPath | ServiceNow Developers</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://restfulapi.net/json-jsonpath/">JSON with JSONPath</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><a href="https://datatracker.ietf.org/doc/rfc9535/">RFC 9535 - JSONPath: Query Expressions for JSON</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://github.com/json-path/JsonPath">GitHub - json-path/JsonPath: Java JsonPath implementation</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p><a href="https://jsonpath.com/">JSONPath Online Evaluator</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>Dynamic countdown message in the portal</title>
      <link>https://www.snow-adventures.com/posts/dynamic-countdown-message-in-the-portal/</link>
      <pubDate>Thu, 20 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/dynamic-countdown-message-in-the-portal/</guid>
      <description>This article explains how to implement a dynamic countdown message in the portal, for example to update a timer in real time</description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<p>This article explains how to implement a dynamic countdown message in the portal. This can be used in various scenarios where a countdown or other variable, dynamic information is updated in the message, like session timeouts, limited-time offers, etc.</p>
<p>For example, it can be a message like &ldquo;You have MM:SS remaining to complete this action&rdquo;.</p>
<video autoplay loop muted playsinline style="width: auto;">
  <source src="/img/dynamiccountdownmessage/dynamic.webm" type="video/webm">
  Your browser does not support the video tag.
</video>
<h1 id="approach">Approach</h1>
<p>The idea is to get the base message with <code>gs.getMessage()</code> in the server script and replace the dynamically the timer using a client script.</p>
<h2 id="why-not-simply-use-a-static-angular-message">Why not simply use a static Angular message</h2>
<p>Angular offers a way to bind dynamic data to the HTML template, but it has limitations when the message itself is partially static with only one part that change dynamically. To my knowledge there isn&rsquo;t a way to easily replace a placeholder (like &ldquo;MM:SS&rdquo;) within the message itself every second.</p>
<h1 id="implementation">Implementation</h1>
<h2 id="server-script">Server Script</h2>
<p>In the Server Script, we basically retrieve the messages and the different options for the time options.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// get the widget options
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">timeout</span><span class="p">;</span> <span class="c1">// initialize the timer, in milliseconds
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">data</span><span class="p">.</span><span class="nx">timeout</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">timeout</span><span class="p">;</span> <span class="c1">// keep the timeout value, used when resetting the time
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// get the count down message
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">data</span><span class="p">.</span><span class="nx">countDownMessage</span> <span class="o">=</span> <span class="nx">gs</span><span class="p">.</span><span class="nx">getMessage</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">countdownmessage</span><span class="p">);</span>
</span></span></code></pre></div><h2 id="client-script">Client script</h2>
<p>In the Client Script, we first need a function to format time in the &ldquo;MM:SS&rdquo; format and set the timer value used in the message:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Set the initial value of the time to display to the user
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Function to convert the millisecond in minutes:seconds (MM:SS) format
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">milliseconds</span><span class="p">){</span> 
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">seconds</span> <span class="o">=</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">milliseconds</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">minutes</span> <span class="o">=</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">seconds</span> <span class="o">/</span> <span class="mi">60</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>   
</span></span><span class="line"><span class="cl">	<span class="nx">seconds</span> <span class="o">=</span> <span class="nx">seconds</span> <span class="o">%</span> <span class="mi">60</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">minutes</span> <span class="o">=</span> <span class="nx">minutes</span> <span class="o">%</span> <span class="mi">60</span><span class="p">;</span>   
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">formattedTime</span> <span class="o">=</span> <span class="nx">minutes</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">padStart</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&#34;:&#34;</span> <span class="o">+</span> <span class="nx">seconds</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">padStart</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">);</span>   
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">formattedTime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Then we need to set the timer for the countdown, that will update the time displayed to the user:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Start updating the timer every second
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$timeout</span><span class="p">(</span><span class="nx">updateTime</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">updateTime</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">	<span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span> <span class="o">-=</span> <span class="mi">1000</span><span class="p">;</span> <span class="c1">// Decrease the timer by 1 second
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">	<span class="c1">// check if the time is over
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// Set the displayed time to zero (so we never show negative time)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="s2">&#34;0&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// perform the required action when time is over, for example redirect somewhere else
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="s2">&#34;/somewhere.do&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">else</span> <span class="cm">/*update counter*/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">$timeout</span><span class="p">(</span><span class="nx">updateTime</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span> <span class="c1">// Update again after 1 second
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>In some cases, we want to reset the countdown, for example when the user is interacting with the page:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Reset the timer when navigating in the page 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$rootScope</span><span class="p">.</span><span class="nx">$on</span><span class="p">(</span><span class="s1">&#39;$locationChangeStart&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">,</span> <span class="nx">newUrl</span><span class="p">,</span> <span class="nx">oldUrl</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">resetTimer</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Reset the timer on click and keydown events
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="nx">resetTimer</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;keydown&#39;</span><span class="p">,</span> <span class="nx">resetTimer</span><span class="p">);</span>   
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Function to reset the timer 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">resetTimer</span><span class="p">()</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">	<span class="c1">// reset the timer 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span> <span class="o">=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeout</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">	<span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="html-template">HTML template</h2>
<p>And the last, but not the least, here is the HTML template. To display the dynamic message, it call the function <code>formatCountDownMessage()</code> with the message and the time in the <em>MM:SS</em> format.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;countdownmessage&#34;</span><span class="p">&gt;</span>{{c.formatCountDownMessage(data.countDownMessage, data.timeMMSS)}}<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>and the corresponding function (in the client script!):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Add the formatCountDownMessage
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">c</span><span class="p">.</span><span class="nx">formatCountDownMessage</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">timeMMSS</span><span class="p">)</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">message</span> <span class="o">||</span> <span class="o">!</span><span class="nx">timeMMSS</span><span class="p">)</span> <span class="k">return</span> <span class="nx">message</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">message</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s1">&#39;MM:SS&#39;</span><span class="p">,</span> <span class="nx">timeMMSS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="putting-all-together-in-the-client-script">Putting all together in the Client Script</h2>
<p>Here is the complete Client Script with all the part detailled above. You can also find the complete widget in the References section below.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">api</span><span class="p">.</span><span class="nx">controller</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">$timeout</span><span class="p">,</span> <span class="nx">$rootScope</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* widget controller */</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Set the initial value of the time to display to the user
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Start updating the timer every second
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">$timeout</span><span class="p">(</span><span class="nx">updateTime</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Reset the timer when navigating in the page 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">$rootScope</span><span class="p">.</span><span class="nx">$on</span><span class="p">(</span><span class="s1">&#39;$locationChangeStart&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">,</span> <span class="nx">newUrl</span><span class="p">,</span> <span class="nx">oldUrl</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">resetTimer</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Reset the timer on click and keydown events
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="nx">resetTimer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;keydown&#39;</span><span class="p">,</span> <span class="nx">resetTimer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Function to update the timer 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">function</span> <span class="nx">updateTime</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span> <span class="o">-=</span> <span class="mi">1000</span> <span class="c1">// Decrease the timer by 1 second
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			
</span></span><span class="line"><span class="cl">        <span class="c1">// check if the time is over
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// Set the displayed time to zero (so we never show negative time)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="s2">&#34;0&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// perform the required action when time is over, for example redirect somewhere else
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="s2">&#34;/somewhere.do&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="cm">/*update counter*/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nx">$timeout</span><span class="p">(</span><span class="nx">updateTime</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span><span class="c1">//  Update again after 1 second
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Function to reset the timer 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">function</span> <span class="nx">resetTimer</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// reset the timer 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span> <span class="o">=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeout</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timeMMSS</span> <span class="o">=</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">timer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Function to convert the millisecond in minutes:seconds (MM:SS) format
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">function</span> <span class="nx">formatMillisecondsToMMSS</span><span class="p">(</span><span class="nx">milliseconds</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nx">seconds</span> <span class="o">=</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">milliseconds</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nx">minutes</span> <span class="o">=</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">seconds</span> <span class="o">/</span> <span class="mi">60</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">seconds</span> <span class="o">=</span> <span class="nx">seconds</span> <span class="o">%</span> <span class="mi">60</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">minutes</span> <span class="o">=</span> <span class="nx">minutes</span> <span class="o">%</span> <span class="mi">60</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nx">formattedTime</span> <span class="o">=</span> <span class="nx">minutes</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">padStart</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&#34;:&#34;</span> <span class="o">+</span> <span class="nx">seconds</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">padStart</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">formattedTime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Add the formatCountDownMessage
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">c</span><span class="p">.</span><span class="nx">formatCountDownMessage</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">message</span><span class="p">,</span> <span class="nx">timeMMSS</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">message</span> <span class="o">||</span> <span class="o">!</span><span class="nx">timeMMSS</span><span class="p">)</span> <span class="k">return</span> <span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">message</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s1">&#39;MM:SS&#39;</span><span class="p">,</span> <span class="nx">timeMMSS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h1 id="references">References</h1>
<p>1.<a href="https://gitlab.com/samuelmeylan/snowadventuresnippets/-/snippets/4784822">A complete example widget is availlable in github</a></p>]]></content:encoded>
    </item>
    
    <item>
      <title>Search on screenshot attachments</title>
      <link>https://www.snow-adventures.com/posts/search-on-screenshot-attachments/</link>
      <pubDate>Sun, 20 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/search-on-screenshot-attachments/</guid>
      <description>OCR on picture attachments with Google vision API</description>
      <content:encoded><![CDATA[<h2 id="ocr-on-attachment-with-google-vision-api">OCR on attachment with Google vision API</h2>
<p>This article shows how to use the Google Vision API to extract text from attachments and to make this text searchable in Service-Now.</p>
<p>In this quick demo, we can see that attaching printscreens to an incident will trigger a call to the Google Vision API and extract the text in a field <em>Extracted field</em> on the attachment table and consolidate all the attachment texts in a field <em>Attachment text</em> on the incident.</p>
<figure>
    <img loading="lazy" src="/img/Search_on_screenshot/Attachment%20OCR%20demo.gif"/> <figcaption>
            Adding attachment triggers OCR and extract text
        </figcaption>
</figure>

<p>Then we can search string that are present only on the screenshots, like &ldquo;Wikipedia&rdquo; or &ldquo;Croissant&rdquo; in this case.</p>
<figure>
    <img loading="lazy" src="/img/Search_on_screenshot/Attachment%20OCR%20demo%20search.gif"/> <figcaption>
            Search with text from the screenshots
        </figcaption>
</figure>

<p>Now, let&rsquo;s see how to implement this solution.</p>
<h2 id="setup-the-google-api">Setup the google APi</h2>
<p>First of all, you will need a Google Cloud account.</p>
<p>If you don&rsquo;t already have a Google Cloud account, you can setup your account here: <a href="https://cloud.google.com/">https://cloud.google.com/</a></p>
<p>When done, go in the Google Cloud console and follow the instruction in the starting guide[1] and in the Detect text in images guide[2].</p>
<p>Basically you will need to:</p>
<ul>
<li>create a new Project</li>
<li><a href="https://console.cloud.google.com/flows/enableapi?apiid=vision.googleapis.com">activate the Vision API</a> for your project</li>
<li>Create an API key in the credential
<ul>
<li>Go in the menu, the &ldquo;API &amp; Services&rdquo; - &ldquo;Credentials&rdquo;
<figure>
	    <img loading="lazy" src="/img/Search_on_screenshot/63d7441b41fac25810743cf4c7ba4f73.png"/> <figcaption>
	            Create API credentials
	        </figcaption>
	</figure>
</li>
<li>Then click &ldquo;Create Credential&rdquo; - &ldquo;API key&rdquo;
<figure>
	    <img loading="lazy" src="/img/Search_on_screenshot/5c09b2c362592fd867aaf05805e5af55.png"/> <figcaption>
	            Create API credentials
	        </figcaption>
	</figure>
</li>
<li>Then copy and keep the key for later reference.</li>
</ul>
</li>
</ul>
<p>You should now be ready to use the google API.</p>
<blockquote>
<p>Obviously, for real life usage, you may want to use other authentification methods and/or add some more security. To do so please refer to the Google Cloud documentation or consult a Google Cloud specialist.</p>
</blockquote>
<h2 id="adapt-the-attachment-table">Adapt the attachment table</h2>
<p>The idea is to store the extracted text from the image in a text field on the attachment table.</p>
<p>Before doing so, I suggest to work in an Scoped Application: so please create and use a new Application &ldquo;OCR Attachment&rdquo;.</p>
<p>Then, let&rsquo;s create a new field <code>u_extracted_text</code> on the table <code>sys_attachment</code>, of type String and of a sufficient size of 4000.</p>
<p>Then we need give access at our application &ldquo;OCR Attachment&rdquo;  to the Attachment table:</p>
<ul>
<li>go in &ldquo;System Definition&rdquo; - &ldquo;Tables&rdquo;</li>
<li>select the sys_attachment table</li>
<li>on the &ldquo;Application Access&rdquo; tab set &ldquo;Can Update&rdquo; to true. <figure>
    <img loading="lazy" src="/img/Search_on_screenshot/bd99ff397e2a5e1ed9200b8d8c00e40c.png"/> <figcaption>
            Create API credentials
        </figcaption>
</figure>
</li>
<li>To avoid potential issues later, please also reset the cache by doing a <code>cache.do</code> in the Filter Navigator.</li>
</ul>
<h2 id="create-the-rest-message">Create the REST message</h2>
<p>Now we need to create a REST message and the corresponding HTTP method.</p>
<p>Simply create a new REST message &ldquo;Google Vision API&rdquo; and set the endpoint to</p>
<pre tabindex="0"><code class="language-url" data-lang="url">https://vision.googleapis.com/v1/images:annotate
</code></pre><p>Then open the prefefined HTTP method that is automatically created when saving the REST message and</p>
<ul>
<li>renamne it to &ldquo;POST&rdquo;</li>
<li>Set the HTTP method to &ldquo;POST&rdquo;</li>
<li>Set the endpoint to <code>https://vision.googleapis.com/v1/images:annotate?key=${apikey}</code></li>
<li>On the &ldquo;HTTP request&rdquo; tab, set the Content to
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="s2">&#34;requests&#34;</span><span class="o">:</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">	  <span class="p">{</span>
</span></span><span class="line"><span class="cl">		 <span class="s2">&#34;image&#34;</span><span class="o">:</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;content&#34;</span><span class="o">:</span><span class="s2">&#34;${base64Image}&#34;</span>
</span></span><span class="line"><span class="cl">		 <span class="p">},</span>
</span></span><span class="line"><span class="cl">		 <span class="s2">&#34;features&#34;</span><span class="o">:</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">			<span class="p">{</span>
</span></span><span class="line"><span class="cl">			   <span class="s2">&#34;type&#34;</span><span class="o">:</span><span class="s2">&#34;TEXT_DETECTION&#34;</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		 <span class="p">]</span>
</span></span><span class="line"><span class="cl">	  <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<p>The important points are the variable names <code>apikey</code> and <code>base64Image</code>, that we will use in the Business Rule later.</p>
<h3 id="testing-the-rest-message">Testing the rest message</h3>
<p>To test you REST message and HTTP request, you can add 2 entries in the Variable Substitution related list:</p>
<ul>
<li>apikey: containing the API you created before in the Google Cloud console</li>
<li>base64Image: containing a base64 encoded image that have text in it.
<ul>
<li>You can use this <a href="https://www.base64-image.de/">online base64 converter</a> to convert your image.</li>
</ul>
</li>
</ul>
<p>Then you can use the <em>test</em> related link and you should get a code 200 and a json string with the text extracted from your image.</p>
<h2 id="create-a-business-rule-on-the-attachment-table">Create a Business Rule on the attachment table</h2>
<p>Now that both the table and the REST message are ready, we can create a new Business Rule:</p>
<ul>
<li>Name : &ldquo;Extract text from image&rdquo;</li>
<li>Table: sys_attachment</li>
<li>Advanced: true</li>
<li>When to Run
<ul>
<li>When: async</li>
<li>On insert</li>
<li>Condition: Extracted Text is Empty and File name ends with .jpg, .jpeg or .png (adapt the list to your taste)</li>
</ul>
</li>
</ul>
<p>The in the <em>Advanced</em> tab, you can use and adapt the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span> <span class="nx">executeRule</span><span class="p">(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span> <span class="cm">/*null when async*/</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// get base64 string from file 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">base64Str</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideSysAttachment</span><span class="p">().</span><span class="nx">getContentBase64</span><span class="p">(</span><span class="nx">current</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// get API key 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">apiKey</span> <span class="o">=</span> <span class="nx">gs</span><span class="p">.</span><span class="nx">getProperty</span><span class="p">(</span><span class="s1">&#39;x_12270_ocr_attach.googleVision_api_key&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="nx">base64Str</span> <span class="o">&amp;&amp;</span> <span class="nx">apiKey</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// build request
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">request</span><span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">(</span><span class="s1">&#39;x_12270_ocr_attach.Google Vision API&#39;</span><span class="p">,</span> <span class="s1">&#39;POST&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="nx">request</span><span class="p">.</span><span class="nx">setStringParameterNoEscape</span><span class="p">(</span><span class="s1">&#39;base64Image&#39;</span><span class="p">,</span> <span class="nx">base64Str</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="nx">request</span><span class="p">.</span><span class="nx">setStringParameterNoEscape</span><span class="p">(</span><span class="s1">&#39;apikey&#39;</span><span class="p">,</span> <span class="nx">apiKey</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// execute request
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// extract response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">responseBody</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			<span class="kd">var</span> <span class="nx">httpStatus</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getStatusCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// if success
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="k">if</span> <span class="p">(</span><span class="nx">httpStatus</span> <span class="o">==</span> <span class="s1">&#39;200&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">				<span class="nx">responseObj</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">				<span class="k">if</span> <span class="p">(</span><span class="nx">responseObj</span> <span class="o">&amp;&amp;</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">responses</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">responses</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">fullTextAnnotation</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">					<span class="kd">var</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">responses</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">fullTextAnnotation</span><span class="p">.</span><span class="nx">text</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">					<span class="k">if</span> <span class="p">(</span><span class="nx">text</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">						<span class="nx">current</span><span class="p">.</span><span class="nx">u_extracted_text</span> <span class="o">=</span> <span class="nx">text</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">						<span class="nx">current</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">					<span class="p">}</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">exception</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error in Business rule &#39;Extract text from image&#39;: &#34;</span> <span class="o">+</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">exception</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span><span class="p">);</span>
</span></span></code></pre></div><p>Then the last step is to create a new system property <code>googleVision_api_key</code> and set there the API key you created from the Google Cloud Console.</p>
<h2 id="searching-tasks-using-attachments-text">Searching tasks using attachment&rsquo;s text</h2>
<p>Now the last part is to be able to search records (like incidents, etc.. ) where the related attachment contains the searched text.</p>
<p>The easiest way for this is to create a new field on the <em>Task</em> table that will contains the extracted text of all the attachments. This way the text contained in this field (the text extracted from the attachments) will be included in the Zing search on tasks.</p>
<p>So, let&rsquo;s create a new field <code>attachment_text</code> on the table <code>task</code>, of type String and of a sufficient size of 4000.</p>
<p>Then we need a new Business Rule on the table <code>sys_attachment</code>:</p>
<ul>
<li>Name : &ldquo;Maintain extracted text on related task&rdquo;</li>
<li>Table: sys_attachment</li>
<li>Advanced: true</li>
<li>When to Run
<ul>
<li>When: after</li>
<li>On insert, update, delete</li>
<li>Condition: Extracted Text changes</li>
</ul>
</li>
<li>Conditions:</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideTableHierarchy</span><span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">table_name</span><span class="p">).</span><span class="nx">getRoot</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&#34;task&#34;</span> <span class="cm">/*check that the related table is child of task*/</span>
</span></span></code></pre></div><p>The in the <em>Advanced</em> tab, add the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span> <span class="nx">executeRule</span><span class="p">(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span> <span class="cm">/*null when async*/</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">try</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// get the related table
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">taskGr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">table_name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">table_sys_id</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// to hold the attachment texts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">attachmentTextObj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// make sure the attachment text field is valid
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="k">if</span> <span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">isValidField</span><span class="p">(</span><span class="s1">&#39;x_12270_ocr_attach_attachment_text&#39;</span><span class="p">)){</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// if the attachment text field exist and is not empty, parse it
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="k">if</span> <span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">x_12270_ocr_attach_attachment_text</span><span class="p">){</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">					<span class="nx">attachmentTextObj</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">taskGr</span><span class="p">.</span><span class="nx">x_12270_ocr_attach_attachment_text</span><span class="p">);</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// if we delete the attachment, remove the corresponding text
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="k">if</span> <span class="p">(</span><span class="nx">current</span><span class="p">.</span><span class="nx">operation</span><span class="p">()</span> <span class="o">==</span> <span class="s1">&#39;delete&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">					<span class="k">delete</span> <span class="nx">attachmentTextObj</span><span class="p">[</span><span class="nx">current</span><span class="p">.</span><span class="nx">getUniqueValue</span><span class="p">()];</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span> <span class="k">else</span> <span class="cm">/*otherwise, set the text*/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">					<span class="nx">attachmentTextObj</span><span class="p">[</span><span class="nx">current</span><span class="p">.</span><span class="nx">getUniqueValue</span><span class="p">()]</span> <span class="o">=</span> <span class="nx">current</span><span class="p">.</span><span class="nx">u_extracted_text</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// Set back the attachment text to string and update
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="nx">taskGr</span><span class="p">.</span><span class="nx">x_12270_ocr_attach_attachment_text</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">attachmentTextObj</span><span class="p">);</span> <span class="cm">/*ADAPT according you Application mame, etc...*/</span>
</span></span><span class="line"><span class="cl">				<span class="nx">taskGr</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">exception</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Error in Business rule &#39;Maintain extracted text on related task&#39;: &#34;</span> <span class="o">+</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">exception</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="testing">Testing</h3>
<p>You can now take a print screen with text in it and attach it to a record like an <em>Incident</em>:</p>
<ul>
<li>The <code>sys_attachment</code> record now have the text extracted in to the <code>Extracted text</code>field.</li>
<li>The <code>incident record</code> record now have also the text in the  <code>attachment_text</code> field.</li>
</ul>
<p>You can now search for a String that is present on the screenshot and you incident should show up in the search result</p>
<h2 id="references">References</h2>
<ol>
<li>Cloud Vision API - Documentation - Quickstart: Setup the Vision API <a href="https://cloud.google.com/vision/docs/setup">https://cloud.google.com/vision/docs/setup</a></li>
<li>Cloud Vision API - Documentation - Detect text in images <a href="https://cloud.google.com/vision/docs/ocr">https://cloud.google.com/vision/docs/ocr</a></li>
</ol>]]></content:encoded>
    </item>
    
    <item>
      <title>Interactive map in the portal</title>
      <link>https://www.snow-adventures.com/posts/interactive-map-in-the-portal/</link>
      <pubDate>Sat, 12 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/interactive-map-in-the-portal/</guid>
      <description>Integrate OpenStreetMap with ServiceNow records in the Portal</description>
      <content:encoded><![CDATA[<p>This article shows how to display records from SericeNow that are related to a location on a map in the ServiceNow portal, using OpenStreetMap (OSM).</p>
<p>For this purpose, we will create a portal Widget and make it interact with a list to show the records related to the choosen location.</p>
<p>Instead of relying on the google map services, it use instead OpenStreetMap (OSM) data <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>To achieve this, it relies on the open-source Javascript library Leafletjs to render interactive maps<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p>
<p>While there are a number of other libraries to render maps, like OpenLayers<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, Leaflet has the advantage of being lighweight and easier to use.</p>
<p>So as we don&rsquo;t need to cope with more complexe stuff like geo projections and handling various geo data sources, Leaflet offer all the functionnalities we need for a simple map and is enough for our needs.</p>
<h3 id="a-simple-use-case">A simple use case&hellip;</h3>
<p>The use case in scope for of this article is quite simple: we want to show the users on a map, grouped by location if there are more than one, and then filter a list of users according the location the we click on the map.</p>
<figure>
    <img loading="lazy" src="/img/interactivemap_1/portaldemo.gif"/> <figcaption>
            Map demo in the portal
        </figcaption>
</figure>

<p>There are mainly 3 parts:</p>
<ol>
<li>Create a Widget to show the map</li>
<li>Query the data for ServiceNow and show them on the map</li>
<li>Enable interaction with the ServiceNow Portal when a location is selected on the map</li>
</ol>
<p>We will now go through all the steps and build incrementally the map widget.</p>
<h3 id="how-leaflet-works">How Leaflet works</h3>
<p>As said before, we are using the Leaflet.js API for all our mapping needs.</p>
<p>Before jumping in ServiceNow to build the widget, I suggest you to take a few minutes to read at least the Leaftet&rsquo;s Quick Start Guide<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<p>The key points are mainly:</p>
<ul>
<li>We need the library and css in the page</li>
<li>The HTML part is very simple, just a <code>&lt;DIV&gt;</code> tag</li>
<li>Then in the code we need:
<ul>
<li>to create the <em>map</em> with <code>L.map</code> and make the link with the <code>&lt;DIV&gt;</code>tag</li>
<li>Use <code>setView</code> to indicate where to center the map and the scale to use</li>
<li>build the <em>tileLayer</em> with <code>L.tileLayer</code>, and that where we incidcate the OpenStreetMap tiles server</li>
<li>Add the <em>features</em> on the map with <code>L.marker</code></li>
<li>We need then to react on click to interract with the portal and also center the map on the clicked feature</li>
</ul>
</li>
</ul>
<h2 id="building-the-map-widget">Building the map widget</h2>
<p>To start buidling the map widget, I recommand using a custom scoped application in ServiceNow.</p>
<p>When your application is created, create a new Portal Widget:</p>
<ul>
<li>Name : Leaflet Map</li>
<li>ID: leaflet_map</li>
</ul>
<h3 id="store-the-leaflet-api-scripts-as-widget-dependencies">store the Leaflet API scripts as widget dependencies</h3>
<p>When creating the dependencies, you can either use a link to the Leaflet script online or store a copy in the ServiceNow instance.</p>
<p>I recommand storing a copy, so we don&rsquo;t depedant on other servers availlability for this part.</p>
<p>To do so, start by downloading the Libraries, either from the UNPKG repository <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> or from the Leaflet web site <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<p>We need the two following files:</p>
<ul>
<li>leaflet.js</li>
<li>leaflet.css</li>
</ul>
<p>Then create a new Widget Dependency called &ldquo;Leaflet&rdquo; and add a new JS include  and a new CSS include containing repectively the content of file <code>leaflet.js</code> and <code>leaflet.css</code>.</p>
<figure>
    <img loading="lazy" src="/img/interactivemap_1/add_dependencies.gif"/> <figcaption>
            Add Leaflet dependencies to the widget
        </figcaption>
</figure>

<h3 id="set-the-html-css-and-client-script-for-a-first-test">Set the HTML, CSS and client script for a first test</h3>
<p>Set the HTML part as follow:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;map&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Then the CSS part:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">#</span><span class="nn">map</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">absolute</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">left</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">500</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">500</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And finally the client script:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">api</span><span class="p">.</span><span class="nx">controller</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="cm">/* widget controller */</span>
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// build the map
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">var</span> <span class="nx">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">L</span><span class="p">.</span><span class="nx">Map</span><span class="p">(</span><span class="s1">&#39;map&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// get the tile layer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="s1">&#39;https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">tilelayer</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">L</span><span class="p">.</span><span class="nx">tileLayer</span><span class="p">(</span><span class="nx">url</span><span class="p">,{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">attribution</span><span class="o">:</span> <span class="s1">&#39;&amp;copy; &lt;a href=&#34;https://www.openstreetmap.org/copyright&#34;&gt;OpenStreetMap&lt;/a&gt; contributors&#39;</span> <span class="cm">/*required as per OSM license - https://www.openstreetmap.org/copyright/en */</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="c1">// add layer to the map
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">map</span><span class="p">.</span><span class="nx">addLayer</span><span class="p">(</span><span class="nx">tilelayer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// set the view
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">var</span> <span class="nx">latitude</span> <span class="o">=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">start_position_latitude</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">longitude</span> <span class="o">=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">start_position_longitude</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">scale</span> <span class="o">=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">start_scale</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">map</span><span class="p">.</span><span class="nx">setView</span><span class="p">(</span><span class="nx">L</span><span class="p">.</span><span class="nx">latLng</span><span class="p">(</span><span class="nx">latitude</span><span class="p">,</span> <span class="nx">longitude</span><span class="p">),</span> <span class="nx">scale</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>As a good practice, we should avoid to hardcode the values in the script and use options instead. So we still need to add this JSON in the <em>Option schema</em> of the widget. You can of course change the default value to suit your needs or change them later in the widget instances.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JSON" data-lang="JSON"><span class="line"><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;start_position_longitude&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;section&#34;</span><span class="p">:</span><span class="s2">&#34;other&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;default_value&#34;</span><span class="p">:</span><span class="s2">&#34;6.6327&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span><span class="s2">&#34;Start position longitude&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">},</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;hint&#34;</span><span class="p">:</span><span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;start_position_latitude&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;section&#34;</span><span class="p">:</span><span class="s2">&#34;other&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;default_value&#34;</span><span class="p">:</span><span class="s2">&#34;46.5218&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span><span class="s2">&#34;Start position latitude&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">},</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;start_scale&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;section&#34;</span><span class="p">:</span><span class="s2">&#34;other&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;default_value&#34;</span><span class="p">:</span><span class="s2">&#34;13&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span><span class="s2">&#34;Start scale&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></div><p>Make sure the widget option <em>Has preview</em> is checked and you can now vizualize the result with the Widget Editor:</p>
<figure>
    <img loading="lazy" src="/img/interactivemap_1/step1_vizualization.png"/> <figcaption>
            Simply showing a map in the widget
        </figcaption>
</figure>

<h2 id="query-the-data-from-servicenow">Query the data from ServiceNow</h2>
<p>Now that we have a map displayed, we need to add informations coming from the ServiceNow tables.</p>
<p>In this example we will show Users from the table <em>sys_user</em>. The position of each user will be determined by the <em>location</em> field.</p>
<p>Then we will use the <em>longitute</em> and <em>latitude</em> from the referenced Location (table <em>cmn_location</em>).</p>
<h3 id="geojson-format">geoJSON format</h3>
<p>To indicate Leaflet what to display and where, we need to provide the API with a <em>geoJSON</em> string <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>.</p>
<p>Each &ldquo;object&rdquo; to put on the map is called a <em>feature</em>.</p>
<p>The GeoJSON standard specify various type of data that can be represented, but the one that suits our needs the best is the <em>FeatureCollection</em>, where multiple <em>Features</em> can be represented (but it work also if there is only one feature).</p>
<p>The format is as follow:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JSON" data-lang="JSON"><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;FeatureCollection&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;features&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">		<span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nt">&#34;geometry&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;Point&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nt">&#34;coordinates&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">					<span class="err">x</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">					<span class="err">y</span>
</span></span><span class="line"><span class="cl">				<span class="p">]</span>
</span></span><span class="line"><span class="cl">			<span class="p">},</span>
</span></span><span class="line"><span class="cl">			<span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;Feature&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nt">&#34;popupContent&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nt">&#34;iconText&#34;</span> <span class="p">:</span> <span class="s2">&#34;iconText&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="nt">&#34;locationId&#34;</span> <span class="p">:</span> <span class="s2">&#34;sys_id of location&#34;</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The <em>properties</em> part is free, so we can set everything we need. For the example, there is</p>
<ul>
<li><em>popupContent</em>, that contains the text to show on a pop-up when clikcing the location,</li>
<li><em>iconText</em> that is shown on the map (will be used for the count of record on each location,</li>
<li><em>locationId</em> that contains the sys_id of the location&rsquo;s record.</li>
</ul>
<h3 id="retrieving-the-data">Retrieving the data</h3>
<p>To retreive the data, we will use a GlideAggregate on the table and group by the location. Note that the table, the name of the field that refernece the location table and the query on the table are coming from the Widget options:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">	<span class="c1">// get the options values
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">var</span> <span class="nx">sourceTableName</span>  <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">features_source_table</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">locationFieldName</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">feature_location_field</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">sourceTableQueryStr</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">feature_table_query</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// get the data from the table to shown as features
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">var</span> <span class="nx">featureGa</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideAggregate</span> <span class="p">(</span><span class="nx">sourceTableName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="p">(</span><span class="nx">sourceTableQueryStr</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">featureGa</span><span class="p">.</span><span class="nx">addEncodedQuery</span><span class="p">(</span><span class="nx">sourceTableQueryStr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">featureGa</span><span class="p">.</span><span class="nx">addNotNullQuery</span><span class="p">(</span><span class="nx">locationFieldName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nx">featureGa</span><span class="p">.</span><span class="nx">addAggregate</span><span class="p">(</span><span class="s1">&#39;COUNT&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nx">featureGa</span><span class="p">.</span><span class="nx">groupBy</span><span class="p">(</span><span class="nx">locationFieldName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nx">featureGa</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span></code></pre></div><h3 id="building-the-geojson">Building the GeoJSON</h3>
<p>To build the GeoJSON, we will use two functions: one to give the main GeoJSON object and another to build each Feature that will be added to the main GeoJSON object.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">	@name getGeoJSONFeaturesCollectionObject
</span></span></span><span class="line"><span class="cl"><span class="cm">	@description get the main GeoJSON Feature Collection Object
</span></span></span><span class="line"><span class="cl"><span class="cm">	@returns {object} GeoJSON Feature collection Object
</span></span></span><span class="line"><span class="cl"><span class="cm">**/</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getGeoJSONFeaturesCollectionObject</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;type&#34;</span><span class="o">:</span> <span class="s2">&#34;FeatureCollection&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;features&#34;</span><span class="o">:</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">		<span class="p">};</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">	@name getFeatureObject
</span></span></span><span class="line"><span class="cl"><span class="cm">	@description Get the Feature part of the GeoJSON
</span></span></span><span class="line"><span class="cl"><span class="cm">	@param {GlideRecord} [loationGr] - GlideRecord from the Location table (cmn_location)
</span></span></span><span class="line"><span class="cl"><span class="cm">	@param {String} [popUpContent=] - Text for the feature&#39;s popup. If not provided, will default to the location&#39;s display value. Can contains &#34;{0}&#34;, that will be replaced by the location&#39;s Display Value
</span></span></span><span class="line"><span class="cl"><span class="cm">	@param {String} [iconText=] - Text to show on the feature&#39;s icon. If not provided, will default to the location&#39;s display value.
</span></span></span><span class="line"><span class="cl"><span class="cm">	@returns {object} GeoJSON Feature collection Object
</span></span></span><span class="line"><span class="cl"><span class="cm">**/</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getFeatureObject</span> <span class="p">(</span><span class="nx">locationGr</span><span class="p">,</span> <span class="nx">popUpContent</span><span class="p">,</span> <span class="nx">iconText</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">popUpContent</span> <span class="o">=</span> <span class="nx">popUpContent</span> <span class="o">||</span> <span class="nx">locationGr</span><span class="p">.</span><span class="nx">getDisplayValue</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="nx">iconText</span> <span class="o">=</span> <span class="nx">iconText</span> <span class="o">||</span> <span class="nx">locationGr</span><span class="p">.</span><span class="nx">getDisplayValue</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;geometry&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="s2">&#34;type&#34;</span><span class="o">:</span> <span class="s2">&#34;Point&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="s2">&#34;coordinates&#34;</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">					<span class="nb">parseFloat</span><span class="p">(</span><span class="nx">locationGr</span><span class="p">.</span><span class="nx">longitude</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">					<span class="nb">parseFloat</span><span class="p">(</span><span class="nx">locationGr</span><span class="p">.</span><span class="nx">latitude</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">				<span class="p">]</span>
</span></span><span class="line"><span class="cl">			<span class="p">},</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;type&#34;</span><span class="o">:</span> <span class="s2">&#34;Feature&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;properties&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="s2">&#34;popupContent&#34;</span><span class="o">:</span> <span class="nx">gs</span><span class="p">.</span><span class="nx">getMessage</span><span class="p">(</span><span class="nx">popupContent</span><span class="p">,</span> <span class="p">[</span><span class="nx">locationGr</span><span class="p">.</span><span class="nx">getDisplayValue</span><span class="p">()]),</span>
</span></span><span class="line"><span class="cl">				<span class="s2">&#34;iconText&#34;</span> <span class="o">:</span> <span class="nx">iconText</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				<span class="s2">&#34;locationId&#34;</span> <span class="o">:</span> <span class="nx">locationGr</span><span class="p">.</span><span class="nx">getUniqueValue</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="p">};</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span></code></pre></div><p>Then we use those functions when looping on the <code>featureGa</code> records to generate the GeoJSON:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">	<span class="c1">// get the GeoJSON object
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kd">var</span> <span class="nx">geoJSONobj</span> <span class="o">=</span> <span class="nx">getGeoJSONFeaturesCollectionObject</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// for each feature
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">while</span> <span class="p">(</span><span class="nx">featureGa</span><span class="p">.</span><span class="nx">next</span><span class="p">()){</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// set the popup content from the options, ot use the displayValue if not set
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">popupContent</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">feature_popup_content</span> <span class="o">||</span> <span class="nx">featureGa</span><span class="p">.</span><span class="nx">getDisplayValue</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">			
</span></span><span class="line"><span class="cl">			<span class="c1">// get the feature object
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">featureObj</span> <span class="o">=</span> <span class="nx">getFeatureObject</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">				<span class="nx">featureGa</span><span class="p">[</span><span class="nx">locationFieldName</span><span class="p">].</span><span class="nx">getRefRecord</span><span class="p">(),</span> <span class="cm">/*get the referenced location record*/</span>
</span></span><span class="line"><span class="cl">				<span class="nx">popupContent</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">				<span class="nx">featureGa</span><span class="p">.</span><span class="nx">getAggregate</span><span class="p">(</span><span class="s1">&#39;COUNT&#39;</span><span class="p">)</span> <span class="cm">/*use the count as the iconText*/</span>
</span></span><span class="line"><span class="cl">			<span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// add in the GeoJSON features
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="nx">geoJSONobj</span><span class="p">.</span><span class="nx">features</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">featureObj</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// set the geoJSON in the data, so it can be used on the client script	
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">data</span><span class="p">.</span><span class="nx">geoJSONobj</span><span class="o">=</span> <span class="nx">geoJSONobj</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="dont-forget-to-add-the-options">Don&rsquo;t forget to add the options&hellip;</h3>
<p>As you may have notice, we use the widet&rsquo;s options to set the table, the fields, and so in the server script. You need to add the following options in the <em>Option Schema</em> of the widget:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JSON" data-lang="JSON"><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;hint&#34;</span><span class="p">:</span><span class="s2">&#34;Name of the table to show as features on the map&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;features_source_table&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;section&#34;</span><span class="p">:</span><span class="s2">&#34;other&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;default_value&#34;</span><span class="p">:</span><span class="s2">&#34;sys_user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span><span class="s2">&#34;Features Source Table&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span><span class="err">,</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;hint&#34;</span><span class="p">:</span><span class="s2">&#34;Name of the field that reference the location on the table shown as features on the map&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;feature_location_field&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;section&#34;</span><span class="p">:</span><span class="s2">&#34;other&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;default_value&#34;</span><span class="p">:</span><span class="s2">&#34;location&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span><span class="s2">&#34;Feature location field&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span><span class="err">,</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;hint&#34;</span><span class="p">:</span><span class="s2">&#34;Query string to apply on the table shown as features on the map&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;feature_table_query&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;section&#34;</span><span class="p">:</span><span class="s2">&#34;other&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;default_value&#34;</span><span class="p">:</span><span class="s2">&#34;location.nameSTARTSWITHLausanne&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span><span class="s2">&#34;Feature table query&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span><span class="err">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;hint&#34;</span><span class="p">:</span><span class="s2">&#34;Supports {0}, that will be replaced by the location display value. Supports HTML.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;feature_popup_content&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;section&#34;</span><span class="p">:</span><span class="s2">&#34;other&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;default_value&#34;</span><span class="p">:</span><span class="s2">&#34;This is the feature &#39;{0}&#39;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span><span class="s2">&#34;Feature popup content&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span></code></pre></div><h2 id="display-the-features-on-the-map">Display the features on the map</h2>
<p>Now that we have a geoJSON availlable, we need to handle it in the client script. For this we will use the API <code>geoJSON</code> function and we will define <code>onEachFeature</code>function that will set up the popup content and trigger the function <code>clickAction</code>when the feature is clicked. We will also define <code>pointToLayer</code> to draw an icon and display the <em>iconText</em> on the map.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">	<span class="kd">var</span> <span class="nx">geoJSONobj</span> <span class="o">=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">geoJSONobj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">L</span><span class="p">.</span><span class="nx">geoJSON</span><span class="p">([</span><span class="nx">geoJSONobj</span><span class="p">],</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nx">onEachFeature</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">feature</span><span class="p">,</span> <span class="nx">layer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// prepare the popup content with the feature&#39;s properties
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">popupContent</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="p">(</span><span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span> <span class="o">&amp;&amp;</span> <span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">popupContent</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">popupContent</span> <span class="o">+=</span> <span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">popupContent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// set the popup content and call clickAction on click
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="nx">layer</span><span class="p">.</span><span class="nx">bindPopup</span><span class="p">(</span><span class="nx">popupContent</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="nx">clickAction</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="nx">pointToLayer</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">feature</span><span class="p">,</span> <span class="nx">latlng</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// prepare the icon text
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">iconText</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="p">(</span><span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span> <span class="o">&amp;&amp;</span> <span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">iconText</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nx">iconText</span> <span class="o">=</span> <span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">iconText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">			
</span></span><span class="line"><span class="cl">			<span class="c1">// create a DIV icon.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">myIcon</span> <span class="o">=</span> <span class="nx">L</span><span class="p">.</span><span class="nx">divIcon</span><span class="p">({</span> 
</span></span><span class="line"><span class="cl">				<span class="nx">className</span><span class="o">:</span> <span class="s1">&#39;map-label-content&#39;</span><span class="p">,</span> <span class="cm">/*important to style it with CSS*/</span>
</span></span><span class="line"><span class="cl">				<span class="nx">iconSize</span><span class="o">:</span> <span class="p">[</span><span class="mi">29</span><span class="p">,</span><span class="mi">29</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">				<span class="nx">html</span><span class="o">:</span><span class="nx">iconText</span> <span class="cm">/*this is the text shown on the map*/</span>
</span></span><span class="line"><span class="cl">			<span class="p">});</span>
</span></span><span class="line"><span class="cl">			
</span></span><span class="line"><span class="cl">			<span class="c1">// return a marker with the icon
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="k">return</span> <span class="nx">L</span><span class="p">.</span><span class="nx">marker</span><span class="p">(</span><span class="nx">latlng</span><span class="p">,</span> <span class="p">{</span><span class="nx">icon</span><span class="o">:</span> <span class="nx">myIcon</span><span class="p">});</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">})</span>
</span></span><span class="line"><span class="cl">		<span class="p">.</span><span class="nx">addTo</span><span class="p">(</span><span class="nx">map</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="kd">function</span> <span class="nx">clickAction</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// center on the clicked feature
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="nx">map</span><span class="p">.</span><span class="nx">setView</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">getLatLng</span><span class="p">(),</span><span class="nx">map</span><span class="p">.</span><span class="nx">getZoom</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span></code></pre></div><p>Then (and this is important, otherwise it doesn&rsquo;t work), we need to define the CSS code for our icon (the one with the class name <code>map-label-content</code>). You can drop this code in the CSS section of the Widget:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-CSS" data-lang="CSS"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">map-label-content</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span><span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="k">border</span><span class="p">:</span><span class="mi">5</span><span class="kt">px</span> <span class="kc">solid</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span><span class="mi">255</span><span class="p">,</span><span class="mi">255</span><span class="p">,</span><span class="mf">0.5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">text-align</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">absolute</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">overflow</span><span class="p">:</span> <span class="kc">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-repeat</span><span class="p">:</span> <span class="kc">no-repeat</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-position</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#fff</span><span class="p">;</span>                    <span class="err">//</span> <span class="err">icon</span> <span class="err">color</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">29</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">29</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">50</span><span class="kt">%</span><span class="p">;</span>             <span class="err">//</span> <span class="err">make</span> <span class="err">a</span> <span class="err">circle</span>
</span></span><span class="line"><span class="cl"> <span class="c">/* line-height: 22pt;*/</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mi">15</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-family</span><span class="p">:</span> <span class="s1">&#39;FontAwesome&#39;</span><span class="p">;</span>     <span class="err">//</span> <span class="err">anything</span> <span class="err">goes</span>
</span></span><span class="line"><span class="cl">  <span class="k">filter</span><span class="p">:</span> <span class="nb">drop-shadow</span><span class="p">(</span><span class="mi">2</span><span class="kt">px</span> <span class="mi">2</span><span class="kt">px</span> <span class="mi">2</span><span class="kt">px</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mf">0.5</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The CSS is probably not perfect, but it does the job. If there is any CSS freaky around that have hints for improvements, please feel free to contact me 🙂.</p>
<figure>
    <img loading="lazy" src="/img/interactivemap_1/features_on_map.png"/> <figcaption>
            The features on the map, with the counter
        </figcaption>
</figure>

<h3 id="a-simpler-alternative">A simpler alternative&hellip;.</h3>
<p>If you want something simpler, without displaying the number of records on each location, you can replace the content of the function <code>pointToLayer</code> with this code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">pointToLayer</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">feature</span><span class="p">,</span> <span class="nx">latlng</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="cm">/* The simpler alternative*/</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">L</span><span class="p">.</span><span class="nx">circleMarker</span><span class="p">(</span><span class="nx">latlng</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">radius</span><span class="o">:</span> <span class="mi">8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fillColor</span><span class="o">:</span> <span class="s2">&#34;#ff7800&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">color</span><span class="o">:</span> <span class="s2">&#34;#000&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">weight</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">opacity</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">fillOpacity</span><span class="o">:</span> <span class="mf">0.8</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>			
</span></span></code></pre></div><p>You can then also drop the CSS part for <code>map-label-content</code></p>
<figure>
    <img loading="lazy" src="/img/interactivemap_1/simple_features_on_map.png"/> <figcaption>
            A sober version of the features
        </figcaption>
</figure>

<h2 id="enable-interaction-with-the-servicenow-portal">Enable interaction with the ServiceNow Portal</h2>
<h3 id="trigger-an-event-from-the-map-when-cliking-a-feature">Trigger an event from the map, when cliking a feature</h3>
<p>The last addition to our map widget is to broadcast an event when a feature is clicked.</p>
<p>To do so, you can simply add this line of code in the <code>clickAction</code> function in the client script of the widget:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">	<span class="c1">// trigger event
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">$rootScope</span><span class="p">.</span><span class="nx">$broadcast</span><span class="p">(</span><span class="s1">&#39;mapFeatureClick&#39;</span><span class="p">,</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">feature</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">locationId</span><span class="p">);</span>
</span></span></code></pre></div><p>This will send an event <code>mapFeatureClick</code> with the sys_id of the location.</p>
<p>Now the map widget is ready, it is time to start preparing the widget responsible for the list and then put them together on a page</p>
<h2 id="a-quick-and-dirty-list-widget">A quick and dirty list widget</h2>
<p>For our list widget, we will clone the existing widget &ldquo;Simple List&rdquo; (widget-simple-list).</p>
<blockquote>
<p>⚠ To avoid the handling the script parts that are using ServiceNow functions that are not availlable in scoped application, I strongly suggest to set your scope to <strong>global</strong>. Otherwise prepare yourself to adapt the Simple List widget clone to make it work in a scoped application&hellip;</p>
</blockquote>
<p>So, make sure to be in the global scope and clone the &ldquo;Simple List&rdquo; widget to &ldquo;List linked to map&rdquo;.</p>
<p>Then add a listener in the client script of you new widget, to react when <code>mapFeatureClick</code> is broadcasted:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">	<span class="nx">$rootScope</span><span class="p">.</span><span class="nx">$on</span><span class="p">(</span><span class="s1">&#39;mapFeatureClick&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">,</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">c</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">locationFilter</span> <span class="o">=</span>  <span class="nx">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="nx">c</span><span class="p">.</span><span class="nx">server</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span>
</span></span></code></pre></div><p>This will set a new variable <code>locationFilter</code> in data.</p>
<p>Then we need to modify the server script to use this  <code>locationFilter</code> to filter the records that are shown on the list:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="cm">/* to insert just after line 30:
</span></span></span><span class="line"><span class="cl"><span class="cm">...
</span></span></span><span class="line"><span class="cl"><span class="cm">if (input &amp;&amp; input.filterText)
</span></span></span><span class="line"><span class="cl"><span class="cm">	gr.addEncodedQuery(options.display_field + &#34;LIKE&#34; + input.filterText)
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">input</span> <span class="o">&amp;&amp;</span> <span class="nx">input</span><span class="p">.</span><span class="nx">locationFilter</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gr</span><span class="p">.</span><span class="nx">addQuery</span><span class="p">(</span><span class="s1">&#39;location&#39;</span><span class="p">,</span> <span class="nx">input</span><span class="p">.</span><span class="nx">locationFilter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">options.title = options.title || gr.getPlural();
</span></span></span><span class="line"><span class="cl"><span class="cm">...
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>You can then save the widget.</p>
<h2 id="creating-the-portal-page-and-test-it">Creating the portal page and test it</h2>
<p>The last step is now to create a simple portal page and add the two widgets to it.</p>
<p>Set the list widget options to query the user table (sys_user) and select the primary and secondary fields.</p>
<p>Then make you have users in the correct location and test you page. The list will be filtered according the location you select on the map.</p>
<figure>
    <img loading="lazy" src="/img/interactivemap_1/portaldemo.gif"/> <figcaption>
            Map demo in the portal
        </figcaption>
</figure>

<h2 id="conclusion">Conclusion</h2>
<p>In this article we created a basic map widget, that can be used to interact with the service portal. There is plenty of room for improvements and for adding extra features, but I believe it is a good starting point.</p>
<p>I enjoyed digging in the geo data and map rendering world and I will probably follow up this article with other implementations, like positionning the map when a record is selected in a list, or displaying a custom floor plan and so on. So stay tuned 😉</p>
<p>Please leave you comments or questions below.</p>
<blockquote>
<p>ℹ All the code for the map widget is availlable in <a href="https://gitlab.com/samuelmeylan/www.snow-adventures.com/-/snippets/2049614">GitLab</a>.</p>
</blockquote>
<h2 id="-important-remarks-about-openstreetmap-server-usage">⚠ IMPORTANT Remarks about OpenStreetMap server usage</h2>
<p>As you probaly noticed, we are using the OpenStreetMap server to get the Tiles for our map. This is perfectly fine for some tests and for playing around, but there are some points that need to be considered if this is going to be used &ldquo;in real life&rdquo;.</p>
<p>The OSM foundation policy <sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> states:</p>
<blockquote>
<p>We are in principle happy for our map tiles to be used by external users for creative and unexpected uses – in contrast to most web mapping providers, which insist that you use only their supplied API.</p>
</blockquote>
<blockquote>
<p>However, OpenStreetMap’s own servers are run entirely on donated resources. They have strictly limited capacity. Heavy use of OSM tiles adversely affects people’s ability to edit the map, and is an abuse of the individual donations and sponsorship which provide hardware and bandwidth. As a result, we require that users of the tiles abide by this tile usage policy.</p>
</blockquote>
<p>Therefore I would recommand to use a commercial Tile server or even to setup your own Tile server for your maps. You can find a list of Tile servers here <sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup> and some information about setting up a Tile server here <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup>.</p>
<hr>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://wiki.openstreetmap.org/wiki/Main_Page">OpenStreetMap wiki</a> - accessed 2020 12 12&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Leaflet web site, <a href="https://leafletjs.com/">Leafletjs.com</a> - accessed 2020 12 12&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>OpenLayers web site, <a href="https://openlayers.org/">OpenLayers.org</a> - accessed 2020 12 12&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Leaflet&rsquo;s Quick Start Guide, <a href="https://leafletjs.com/examples/quick-start/">Quick Start Guide</a> - accessed 2020 12 12&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>UNPKG leaflet repository, <a href="https://unpkg.com/browse/leaflet@1.7.1/dist/">unpkg.com</a> - version 1.7.1&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Leaflet&rsquo;s download page, [<a href="https://leafletjs.com/download.html">Leafletjs.com</a> - version 1.7.1&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>GeoJSON web site, <a href="https://geojson.org/">geojson.org</a> - accessed 2020 12 12&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>IETF RFC7946, Butler, et al., <a href="https://tools.ietf.org/html/rfc7946">rfc7946</a> - 1996&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>OSM foundation, <a href="https://operations.osmfoundation.org/policies/tiles/">Tile Usage Policy</a> - accessed 2020 12 12&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>OpenStreetMap wiki, <a href="https://wiki.openstreetmap.org/wiki/Tile_servers">Tile servers</a> - accessed 2020 12 12&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p><a href="https://openmaptiles.org/">OpenMapTiles</a>  - accessed 2020 12 12&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>Playing with the Transformation Service Plugin</title>
      <link>https://www.snow-adventures.com/posts/playing-with-the-transformation-service-plugin/</link>
      <pubDate>Fri, 26 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/playing-with-the-transformation-service-plugin/</guid>
      <description>Overview and usage of the Transformation Service Plugin</description>
      <content:encoded><![CDATA[<h1 id="transformation-service-plugin">Transformation Service Plugin</h1>
<p>The plugin &ldquo;Transformation Service Plugin&rdquo; provides a transfomer API that allows to process JSON or XML data by applying transformations and rules and returning a key/value object with the result.</p>
<p>We will see in this post how it work and what are the limitations and  go through a few examples.</p>
<p>Before going further, make sure that the plugin &ldquo;Transformation Service Plugin&rdquo; (<code>com.glide.transform</code>) is activated in your instance. If not activate it.</p>
<h1 id="overview-of-the-api">Overview of the API</h1>
<p>There are in fact 3 APIs designed to work together to achieve the transformation of the data.</p>
<p>The 3 APIs are:</p>
<ul>
<li><code>Transformer</code> API, that provide the necessary functions to perform the transformation and retrieve the results;</li>
<li><code>TransformerDefinition</code> API, that allows to define the transformation, using a set of rules and a path;</li>
<li><code>TransformerRuleList</code> API, used to defined the transform rules to apply.</li>
</ul>
<p>In a nutshell, you need to create all the transformation rules with <code>TransformerRuleList</code>, add the rules list to the  <code>TransformerDefinition</code> and use the this definition with <code>Transformer</code> to actually process and transform the data.</p>
<h1 id="test-case">Test case</h1>
<p>For this post, we will use data coming from the user table, via a REST api call.</p>
<p>For the sack of simplicity, we will connect to the same instance. The goal here is just to get the data in a JSON format and play with the transform functionnality.</p>
<p>If necessary, for the REST message creation, you can have a look to the post about <a href="/blog/2020-06-10-using-remote-tables-in-service-now/">Using Remote Tables in Service-Now</a>, as we are reusing the message here.</p>
<p>From now, we will aways use the following code to get the data with the subsequent examples:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">r</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">(</span><span class="s1">&#39;x_12270_remote_tab.my users&#39;</span><span class="p">,</span> <span class="s1">&#39;Get&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">r</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">responseBody</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">();</span>
</span></span></code></pre></div><p>As a result, we get a JSON like this one, containig all the fields from the user table in the variable <code>responseBody</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-JSON" data-lang="JSON"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;result&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;calendar_integration&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;country&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;user_password&#34;</span><span class="p">:</span> <span class="s2">&#34;jF9fbZrY7c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;last_login_time&#34;</span><span class="p">:</span> <span class="s2">&#34;2019-04-05 22:16:30&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;source&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="err">....</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="err">.....</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h1 id="transformation-rules">Transformation rules</h1>
<p>The first step is to define the transformation rules.</p>
<p>In our scenario we will start with rules to :</p>
<ul>
<li>Concatenate the <code>first_name</code> and <code>last_name</code> and add a String &ldquo;User &quot; in front;</li>
<li>Replace the &ldquo;email&rdquo; user name by stars (&rdquo;***&quot;), but keep the domain part (&ldquo;<a href="mailto:user@domain.com">user@domain.com</a>&rdquo; becomes &ldquo;***@domain.com&rdquo;);</li>
<li>Define a &ldquo;type&rdquo;, that is either ACTIVE, INACTIVE, based on <code>active</code> field;</li>
<li>Use a few more fields as it</li>
</ul>
<p>This gives us the following code, wrapped in a function <code>getTransformerRuleList</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getTransformerRuleList</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">transformerRuleList</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_tfrm</span><span class="p">.</span><span class="nx">TransformerRuleList</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">fromJSON</span><span class="p">()</span> <span class="cm">/* indicate it is from JSON*/</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">setName</span><span class="p">(</span><span class="s1">&#39;Margin per users&#39;</span><span class="p">)</span> <span class="cm">/*name of the rule list*/</span>
</span></span><span class="line"><span class="cl">  <span class="cm">/* Rules for user concatenated name */</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">addRule</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;$.first_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">addRule</span><span class="p">(</span><span class="s1">&#39;last_name&#39;</span><span class="p">,</span> <span class="s1">&#39;$.last_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">addRule</span><span class="p">(</span><span class="s1">&#39;user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">thenConcat</span><span class="p">(</span><span class="s1">&#39;User &#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">thenConcatSymbol</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">thenConcat</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">thenConcatSymbol</span><span class="p">(</span><span class="s1">&#39;last_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="cm">/* Rules for email */</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">addRule</span><span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="s1">&#39;$.email&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">thenSplit</span><span class="p">(</span><span class="s1">&#39;@&#39;</span><span class="p">,</span> <span class="s1">&#39;***@$2&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="cm">/* Rules for active field*/</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">addRule</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="s1">&#39;$.active&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">thenApplyMap</span><span class="p">({</span><span class="s1">&#39;true&#39;</span><span class="o">:</span> <span class="s1">&#39;ACTIVE&#39;</span><span class="p">,</span> <span class="s1">&#39;false&#39;</span><span class="o">:</span><span class="s1">&#39;INACTIVE&#39;</span><span class="p">});</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">transformerRuleList</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The <code>.fromJSON()</code> is here to indicate that we will parse a JSON source. We would use <code>.fromXML() </code>in case of an XML source.</p>
<p>Then the <code>.setName()</code>is used to give a name to the rule list.</p>
<p>For the rules themself, the logic is always to add a new rule with <code>.addRule()</code> where we give the resulting <em>name</em>  and then where the value is coming from in the source. For example <code>.addRule('first_name', '$.first_name')</code>.</p>
<p>After the <code>.addRule()</code>, we can add one or several <code>.thenSomething</code> method to further modify the value, like for example concatenate with <code>.thenConcat</code>, map with <code>.thenMap</code> and so on. You can find the full list in the API documentation.</p>
<h1 id="executing-the-transformation">executing the transformation</h1>
<p>Now that the rules are defined, we can create a <code>TransformerDefinition</code>and start the transformation with <code>Transformer</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Create a transformer definition and use the rule list and the record path 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">path</span> <span class="o">=</span> <span class="s1">&#39;$.result.*&#39;</span><span class="p">;</span>  <span class="c1">// all the records in the JSON are below &#34;result&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">transformerDefinition</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_tfrm</span><span class="p">.</span><span class="nx">TransformerDefinition</span><span class="p">(</span><span class="nx">getTransformerRuleList</span><span class="p">(),</span> <span class="nx">path</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="c1">// Instantiate the transformer object.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">transformer</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_tfrm</span><span class="p">.</span><span class="nx">Transformer</span><span class="p">(</span><span class="nx">transformerDefinition</span><span class="p">,</span> <span class="nx">responseBody</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Transform all the records of the source, push them in array results and display the the row
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">results</span> <span class="o">=</span> <span class="p">[];</span> 
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span><span class="nx">transformer</span><span class="p">.</span><span class="nx">transform</span><span class="p">())</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">row</span> <span class="o">=</span> <span class="nx">transformer</span><span class="p">.</span><span class="nx">getRow</span><span class="p">()</span> 
</span></span><span class="line"><span class="cl">  <span class="nx">results</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">row</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">row</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> 
</span></span></code></pre></div><p><code>transform()</code>is executing the transaction for the next row and <code>getRow()</code> retrieve the row, in the form of an object with key-value pairs, as defined in the rule list.</p>
<h1 id="calculation-failure">Calculation failure</h1>
<p>I wanted to explore the calculation functions provided and see how it works. Unfortunatly I couldn&rsquo;t make them work when involving two differents elements from the source.</p>
<p>For example, in order to play with the calculations, I added some fields to the user table:</p>
<ul>
<li>Two currency fields
<ul>
<li><code>u_invoiced_price_per_hour</code></li>
<li><code>u_cost_per_hour</code></li>
</ul>
</li>
<li>and on integer field:
<ul>
<li><code>u_hours_by_day</code></li>
</ul>
</li>
</ul>
<p>Then I tried to calculate the margin price for a user by substracting the <code>u_cost_per_hour</code> from <code>u_invoiced_price_per_hour</code>.</p>
<p>According the documentation it can be achieved by adding the following code to the <code>getTransformerRuleList</code> function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="cm">/* Rules for margin */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nx">addRule</span><span class="p">(</span><span class="s1">&#39;margin&#39;</span><span class="p">,</span> <span class="s1">&#39;$.u_invoiced_price_per_hour&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nx">thenSubtract</span><span class="p">(</span><span class="s1">&#39;$.u_cost_per_hour&#39;</span><span class="p">);</span>
</span></span></code></pre></div><p>Unfortunatly it doesn&rsquo;t work and return errors like this one:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Evaluator: java.lang.NumberFormatException
</span></span><span class="line"><span class="cl">   Caused by error in script at line 21
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">     18: } 
</span></span><span class="line"><span class="cl">     19: 
</span></span><span class="line"><span class="cl">     20: function getTransformerRuleList () {
</span></span><span class="line"><span class="cl">==&gt;  21:     var transformerRuleList = new sn_tfrm.TransformerRuleList()
</span></span><span class="line"><span class="cl">     22:         .fromJSON() /* indicate it is from JSON*/
</span></span><span class="line"><span class="cl">     23:         .setName(&#39;Margin per users&#39;) /*name of the rule list*/
</span></span><span class="line"><span class="cl">     24:         /* Rules for user concatenated name */
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">java.math.BigDecimal.&lt;init&gt;(BigDecimal.java:497)
</span></span><span class="line"><span class="cl">java.math.BigDecimal.&lt;init&gt;(BigDecimal.java:827)
</span></span><span class="line"><span class="cl">com.glide.transform.adapter.CalculationAdapterRule.&lt;init&gt;(CalculationAdapterRule.java:222)
</span></span><span class="line"><span class="cl">com.glide.transform.adapter.CalculationAdapterRule.createMultiplicationAdapterRule(CalculationAdapterRule.java:60)
</span></span><span class="line"><span class="cl">com.glide.transform.transformer.AdapterRuleBuilder.thenSubtract(AdapterRuleBuilder.java:78)
</span></span><span class="line"><span class="cl">com.glide.transform.transformer.js.TransformerRuleList.jsFunction_thenSubtract(TransformerRuleList.java:85)
</span></span><span class="line"><span class="cl">sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
</span></span><span class="line"><span class="cl">sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
</span></span><span class="line"><span class="cl">sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
</span></span><span class="line"><span class="cl">java.lang.reflect.Method.invoke(Method.java:498)
</span></span><span class="line"><span class="cl">... 
</span></span></code></pre></div><p>I try various syntaxes, I try adding a <code>parseInt()</code>and so on, but I couldn&rsquo;t make it work.</p>
<p>The only way it work was to replace the <code>'$.u_cost_per_hour'</code> by a number, like in the code below, but this would not by useful in our case.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="cm">/* Rules for margin */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nx">addRule</span><span class="p">(</span><span class="s1">&#39;margin&#39;</span><span class="p">,</span> <span class="s1">&#39;$.u_invoiced_price_per_hour&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nx">thenSubtract</span><span class="p">(</span><span class="mi">15</span><span class="p">);</span> <span class="cm">/*.thenSubtract(&#39;$.u_cost_per_hour&#39;);*/</span>
</span></span></code></pre></div><h1 id="alternative">Alternative</h1>
<p>Bases on this tests, I have the feeling that simply parsing the JSON and performing the necessary transformation directly would be easier and more flexible.</p>
<p>For example, we can achieve the same without using the Transformation Service Plugin with a script like this one:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// parse the response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">responseObj</span> <span class="o">=</span> <span class="nx">global</span><span class="p">.</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// get the records/rows inside the &#34;result&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">records</span> <span class="o">=</span> <span class="nx">responseObj</span><span class="p">[</span><span class="s2">&#34;result&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">altResults</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Loop all records[i]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">records</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">resultObj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">first_name</span> <span class="o">=</span> <span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">first_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">last_name</span> <span class="o">=</span> <span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">last_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">user</span> <span class="o">=</span> <span class="s2">&#34;User &#34;</span> <span class="o">+</span> <span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">first_name</span> <span class="o">+</span> <span class="s2">&#34; &#34;</span> <span class="o">+</span> <span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">last_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// email
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">var</span> <span class="nx">email</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">email</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">&#39;@&#39;</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span> <span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nx">email</span> <span class="o">=</span>  <span class="s2">&#34;***@&#34;</span> <span class="o">+</span> <span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">email</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;@&#39;</span><span class="p">)[</span><span class="mi">1</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">email</span> <span class="o">=</span> <span class="nx">email</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// active field
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">var</span> <span class="nx">active</span> <span class="o">=</span> <span class="s2">&#34;ACTIVE&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">active</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nx">active</span> <span class="o">=</span> <span class="s2">&#34;INACTIVE&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">active</span> <span class="o">=</span> <span class="nx">active</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// margin
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">invoicePriceHour</span> <span class="o">=</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">u_invoiced_price_per_hour</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">u_invoiced_price_per_hour</span> <span class="o">=</span> <span class="nx">invoicePriceHour</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">costHour</span> <span class="o">=</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">records</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">u_cost_per_hour</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">u_cost_per_hour</span> <span class="o">=</span> <span class="nx">costHour</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nx">resultObj</span><span class="p">.</span><span class="nx">margin</span> <span class="o">=</span> <span class="nx">invoicePriceHour</span> <span class="o">-</span> <span class="nx">costHour</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">altResults</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">resultObj</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">resultObj</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> 
</span></span></code></pre></div><p>It is quite straightforward and easy to follow for any ServiceNow developper.</p>
<h2 id="performances">Performances</h2>
<p>Also it seems that using Transformation Service Plugin is a bit slower than the JSON parsing alternative.</p>
<p>To figure out how much slower exactly, I added some code to record the time before and after the &ldquo;transformer&rdquo; script and the &ldquo;parser&rdquo; script and calculate the duratio in milliseconds. Here are the results:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">transfomerStart=1592997620426, transfomerEnd=1592997620556, total=130
</span></span><span class="line"><span class="cl">parserStart=1592997620556, parserEnd=1592997620581, total=25
</span></span></code></pre></div><p>I ran it several time and get always similar results, with the &ldquo;transformer&rdquo; script running about 5 times slower the the &ldquo;parser&rdquo; script.</p>
<h1 id="conclusions">Conclusions</h1>
<p>My guess is that it will still be improved and the issues will resolved, but for the time being, unless there is a very specifc reason, I would avoid using this plugin.</p>
<p>For example, it is a pitty that I could not make the calculation work. I odn&rsquo;t know if I am doing something wrong or if the functionnality is somehow broken, but this would be very usefull.</p>
<p>It is not possible to handle conditional cases by setting values based on the values of other fields.</p>
<p>Also when performing mapping, there is no way to reject the value in case it is not in the mapping definition. similarly, there is no possibility to use a default value in such case.</p>
<p>In my opinion, it is (still?) not as flexible and versatile as using a JSON (or XML) parser directly and adding the necessary code to perform all the concatenations, controls, mapping and calculation directly.</p>
<p>However, I am speaking from my point of view and having in mind the transformations I need to perform regularly. But there should be use cases where this plugin is usefull and where it would be advantageous to use it, but I am currently not aware of them.</p>
<h2 id="references">References</h2>
<blockquote>
<p>⚠ When I last checked I noticed that the current documentation for the API is not 100% accurate. For example <code>.fromJSON()</code> and <code>.fromXML()</code> are not detailed (they are just mentionned in the introduction) and in the examples there is sometime methods that doesn&rsquo;t exist, like a <code>.addMultiply</code>. Also the examples involving calculation using elements of the source are not working well, as we saw above.</p>
</blockquote>
<ol>
<li>ServiceNow documentation, <a href="https://developer.servicenow.com/dev.do#!/reference/api/orlando/server/sn_tfrm-namespace/TransformerScriptedAPI">Transformer API</a>,  accessed 2020 06 22</li>
<li>ServiceNow documentation, <a href="https://developer.servicenow.com/dev.do#!/reference/api/orlando/server/sn_tfrm-namespace/TransformerDefinitionAPI">TransformerDefinition API</a>,  accessed 2020 06 22</li>
<li>ServiceNow documentation, <a href="https://developer.servicenow.com/dev.do#!/reference/api/orlando/server/sn_tfrm-namespace/TransformerRuleListAPI">TransformerRulesList API</a>, accessed 2020 06 22</li>
<li><em>complete script snippet</em> can be accessed <a href="https://gitlab.com/samuelmeylan/www.snow-adventures.com/snippets/1989764">here</a></li>
</ol>]]></content:encoded>
    </item>
    
    <item>
      <title>Global Apps in the Studio</title>
      <link>https://www.snow-adventures.com/posts/global-apps-in-the-studio/</link>
      <pubDate>Mon, 15 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/global-apps-in-the-studio/</guid>
      <description>How to manage Global Apps in the developper Studio</description>
      <content:encoded><![CDATA[<h1 id="managing-global-apps-in-the-studio">Managing global apps in the Studio</h1>
<p>Since the Orlando release, it is possibe to use the Studio to develop Applications in the Global Scope.</p>
<p>We will see in this post how to achieve this and what are the limitations compared to scoped applications in the Studio.</p>
<h2 id="why-use-the-studio-for-global-apps">Why use the Studio for Global Apps?</h2>
<p>Before jumping in the <em>how</em>, let&rsquo;s take a minute to summarize the <em>why</em> would we use the Studio for global applications.</p>
<p>Using the Studio offers several advantages for the developpement:</p>
<ul>
<li>Leverage the publication of the apps, instead of using update sets;</li>
<li>Apply protecttion to the application&rsquo;s assets: you can grab for example a change done to incident and protect it</li>
<li>Use the Studio interface for developpment
<ul>
<li>Create new files from Studio</li>
<li>Use the Application Explorer</li>
<li>Code Search</li>
<li>Work on multiple files with the tabbed interfaces</li>
<li>and so on&hellip;</li>
</ul>
</li>
</ul>
<h2 id="enable-the-global-scope-in-the-studio">Enable the global scope in the Studio</h2>
<p>First step is to enable or allow the <em>global</em> scope in the Studio.</p>
<p>To do so, we need to add a system property: set (or create of it do not exist) the system property <code>sn_g_app_creator.allow_global</code> and set it to <code>true</code>.</p>
<h2 id="lets-create-a-global-application">Let&rsquo;s create a Global application</h2>
<p>To create a Global application, go to the <em>System Applications - My Company Applications</em> and click <em>Create New</em>.</p>
<p>Then fill the Name, the description and under <em>Advanced settings</em> choose <strong>Global</strong>. Then click <em>Create</em>.</p>
<figure>
    <img loading="lazy" src="/img/globalAppInStudio/My%20Company%20Applications.png"/> <figcaption>
            My Company Application...
        </figcaption>
</figure>

<p>You can then continue the wizard as with a Scoped application or just click <em>Continue in Studio (Advanced)</em> if you don&rsquo;t want to create roles, tables, etc.. now.</p>
<h2 id="adding-existing-files">Adding existing files</h2>
<p>In the studio, you can create new files or you can also import existing files from the Global Scope into your application.</p>
<figure>
    <img loading="lazy" src="/img/globalAppInStudio/Add%20files.png"/> <figcaption>
            Create, add or remove files from studio
        </figcaption>
</figure>

<p>When adding existing files, there are three options:</p>
<ul>
<li>Add by update set: this will import the content of the udpate set in the app</li>
<li>Add a table</li>
<li>Add by name: providing the name of the element to add in the app</li>
</ul>
<figure>
    <img loading="lazy" src="/img/globalAppInStudio/Add%20existing%20files.png"/> <figcaption>
            Create, add or remove files from studio
        </figcaption>
</figure>

<h2 id="limitations">Limitations</h2>
<p>There is no source control availlable on Global Application. The reason is that it would take the instance name and then can cause troubles when deploying somewhere else. Also the way it work now is that it deploy all the files and doing do in the Global can lead to important files to be overwritten and so on.</p>
<p>But this will change with the Paris release: ServiceNow will offer Git repository support for Global Scope via ‘delta loading&rsquo;. The delta will avoid overwritting of essential files.</p>
<h3 id="working-with-the-visual-studio-extension">Working with the Visual Studio extension</h3>
<p>In my tests, I could not edit the existing files added to the application from the Visual Studio. How ever, I could edit files that were created from the applications.</p>
<h2 id="references">References</h2>
<ol>
<li>Chuck Tomasi, <a href="https://www.youtube.com/watch?v=ttBKE8w05cs">NOWCommunity Live Stream - Topical Deep Dive - Global apps in Studio</a>, broadcasted 2020 04 23</li>
<li>ServiceNow documentation, <a href="https://docs.servicenow.com/bundle/orlando-application-development/page/build/guided-app-creator/task/gac-activate-global.html">Allow global application development in Guided Application Creator</a>,  accessed 2020 06 15</li>
<li>ServiceNow documentation, <a href="https://docs.servicenow.com/bundle/orlando-application-development/page/build/applications/concept/manage_global_application_files.html">Global application file management</a>,  accessed 2020 06 15</li>
</ol>]]></content:encoded>
    </item>
    
    <item>
      <title>Overview of GlideQuery</title>
      <link>https://www.snow-adventures.com/posts/overview-of-glidequery/</link>
      <pubDate>Wed, 10 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/overview-of-glidequery/</guid>
      <description>Insights about the new GlideQuery functionnality</description>
      <content:encoded><![CDATA[<h1 id="overview-of-glidequery">Overview of GlideQuery</h1>
<p>This overview is mostly a coming from the breakout presentation done by <a href="https://events.servicenow.com/widget/servicenow/knowledge2020/myagenda/session/1581555110988001mNP1?sessionId=1581555110988001mNP1">Peter Bell during knowledge 2020</a>.</p>
<p>Currently this feature is not available in the platform but is part of the ITAM plugin. However it will likely be available in future releases like Paris or Quebec.</p>
<p>In the meantime, it is possible to activate <code>GlideQuery</code>in your personal instance. See below the instructions to do so.</p>
<p>There is also a <a href="../glidequery-cheat-sheet/">Cheat Sheet</a> available for help you playing around with this functionnality.</p>
<h2 id="what-is-glidequery">What is GlideQuery</h2>
<ul>
<li><code>GlideQuery</code> is Server script API
<ul>
<li>it consists of 2 global script includes:
<ul>
<li><code>GlideQuery</code>, to which we can have a look (non protected)</li>
<li><code>GlideQueryEvaluator</code>, which is protected, therefore it is not possible to have a look at it.</li>
</ul>
</li>
</ul>
</li>
<li>It is said that it use <code>GlideRecord</code> under the hood, probably inside the <code>GlideQueryEvaluator</code> script</li>
<li>It also replace <code>GlideAggregate</code> in some cases (in particular for counting records)</li>
<li>it is 100% JavaScript.</li>
</ul>
<p>So it will not replace <code>GlideRecord</code>, but it proposes an additional layer on the top of it, that offers several benefits to the developers. Mainly it should reduce the likelihood of errors and mistakes when manipulating <code>GlideRecord</code> and make it&rsquo;s usage clearer and easier.</p>
<h2 id="three-principles-of-glidequery">Three principles of GlideQuery</h2>
<p>Peter Bell states that <code>GlideQuery</code> has 3 principles, that are:</p>
<ul>
<li>Fail fast: runs into errors as soon as possible, offering a quick feedback loop</li>
<li>Be JavaScript: behave like a normal JavaScript library. The <code>GlideRecord</code> is sometime confusing and behave more like Java.</li>
<li>Be expressive: allows to do more with less code</li>
</ul>
<p>We will se below more in details what that means.</p>
<h3 id="fail-fast">Fail fast</h3>
<p>By &ldquo;Fail fast&rdquo; it means that the query should run into error if anything is potentially wrong and therefore this can be spotted and corrected early. For example:</p>
<ul>
<li>Field name checking</li>
<li>Choice value checking</li>
<li>Type checking</li>
<li>Check if any Business Rule rejects the update/insert</li>
</ul>
<p>Here below are some examples that shows the differences between <code>GlideRecord</code> and <code>GlideQuery</code></p>
<h4 id="field-name-checking">Field Name Checking</h4>
<p><code>GlideQuery</code>checks that the field name used in the query are valid and if not it will raise an error.</p>
<p>For example, running the following code with <code>GlideRecord</code>, it will delete <em>all</em> the records from the Users table, even if the field <code>activated</code> is wrong:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">gr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">addQuery</span><span class="p">(</span><span class="s1">&#39;actived&#39;</span><span class="p">,</span> <span class="s1">&#39;!=&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">getRowCount</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">deleteMultiple</span><span class="p">();</span>
</span></span></code></pre></div><p>If we run the equivalent with <code>GlideQuery</code>, it will fail and give an error instead:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;activated&#39;</span><span class="p">,</span> <span class="s1">&#39;!=&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">del</span><span class="p">();</span>
</span></span></code></pre></div><p>This will return an error:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">*** Script: Unknown field &#39;closed_date&#39; in table &#39;task&#39;. Known fields:
</span></span><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">  &#34;parent&#34;,
</span></span><span class="line"><span class="cl">  &#34;made_sla&#34;,
</span></span><span class="line"><span class="cl">  ...
</span></span><span class="line"><span class="cl">]
</span></span></code></pre></div><h4 id="choice-value-checking">Choice value checking</h4>
<p><code>GlideQuery</code>is also checking for the choice value when choice fields are involved in the query.</p>
<p>For example, running the following code with <code>GlideRecord</code>, it will not return anything.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">gr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">addQuery</span><span class="p">(</span><span class="s1">&#39;approval&#39;</span><span class="p">,</span> <span class="s1">&#39;donotexist&#39;</span><span class="p">);</span> <span class="c1">// we use an invalid value for the choice field &#39;approval&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">gr</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">next</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">getDisplayValue</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>If we run the equivalent with <code>GlideQuery</code>, it will fail and give an error instead:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">tasks</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;approval&#39;</span><span class="p">,</span> <span class="s1">&#39;donotexist&#39;</span><span class="p">)</span> <span class="c1">// we use an invalid value for the choice field &#39;approval&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;number&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">gs</span><span class="p">.</span><span class="nx">log</span><span class="p">);</span>
</span></span></code></pre></div><p>This will return an error:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">*** Script: Invalid choice &#39;donotexist&#39; for field &#39;approval&#39; (table &#39;task&#39;). Allowed values:
</span></span><span class="line"><span class="cl">[
</span></span><span class="line"><span class="cl">  &#34;not requested&#34;,
</span></span><span class="line"><span class="cl">  &#34;requested&#34;,
</span></span><span class="line"><span class="cl">  &#34;approved&#34;,
</span></span><span class="line"><span class="cl">  &#34;rejected&#34;,
</span></span><span class="line"><span class="cl">  &#34;cancelled&#34;,
</span></span><span class="line"><span class="cl">  &#34;not_required&#34;,
</span></span><span class="line"><span class="cl">  &#34;duplicate&#34;
</span></span><span class="line"><span class="cl">]: no thrown error
</span></span></code></pre></div><p>Strangely, it seems to work only with choice fields that have String value. For example this code do not raise any error, despite the state 8 doesn&rsquo;t exist</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">tasks</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;state&#39;</span><span class="p">,</span> <span class="mi">8</span> <span class="cm">/*do not exist!*/</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;number&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">gs</span><span class="p">.</span><span class="nx">log</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="type-checking">Type checking</h3>
<p><code>GlideQuery</code>is also checking if there the value is of the correct type. For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">tasks</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;approval&#39;</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="c1">// we pass an Integer instead of a String
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;number&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">gs</span><span class="p">.</span><span class="nx">log</span><span class="p">);</span>
</span></span></code></pre></div><p>Will return an error:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">** Script: Unable to match value 3 with field &#39;approval&#39; in table &#39;task&#39;. Expecting type &#39;string&#39;: no thrown error
</span></span><span class="line"><span class="cl">Root cause of JavaScriptException: org.mozilla.javascript.NativeError
</span></span></code></pre></div><h4 id="check-if-any-business-rule-rejects-the-updateinsert">Check if any Business Rule rejects the update/insert</h4>
<p>This is another difference with <code>GlideRecord</code>: when a Business Rule abort the insert or update action, then the script would continue, ignoring this error. With <code>GlideQuery</code>, it would rather stop.</p>
<p>For example, running the following code with <code>GlideRecord</code>, it will continue executing, despite that a business rule aborted the action due to start date being after the end date.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">gr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;change_request&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;c83c5e5347c12200e0ef563dbb9a7190&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">setValue</span><span class="p">(</span><span class="s1">&#39;work_end&#39;</span><span class="p">,</span> <span class="s1">&#39;2016-01-01&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">setValue</span><span class="p">(</span><span class="s1">&#39;work_start&#39;</span><span class="p">,</span> <span class="s1">&#39;2020-01-01&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">update</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;executing this line?&#34;</span><span class="p">);</span> <span class="c1">//yes, it will execute this line despite the error in the Business rule preventing the start data after the end date
</span></span></span></code></pre></div><p>If we run the equivalent with <code>GlideQuery</code>, it will fail and give an error instead:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;change_request&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;sys_id&#39;</span><span class="p">,</span> <span class="s1">&#39;c83c5e5347c12200e0ef563dbb9a7190&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">update</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    	<span class="nx">work_end</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GlideDateTime</span><span class="p">(</span><span class="s1">&#39;2016-01-01&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    	<span class="nx">work_start</span><span class="o">:</span> <span class="k">new</span> <span class="nx">GlideDateTime</span><span class="p">(</span><span class="s1">&#39;2020-01-01&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;executing this line?&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>This will return an error:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">*** Script: {
</span></span><span class="line"><span class="cl">  &#34;message&#34;: &#34;Failure to update table&#34;,
</span></span><span class="line"><span class="cl">  &#34;table&#34;: &#34;change_request&#34;,
</span></span><span class="line"><span class="cl">  &#34;lastGlideError&#34;: &#34;Operation against file &#39;change_request&#39; was aborted by Business Rule &#39;Actual Start/End Date Validation^c83c5e5347c12200e0ef563dbb9a7190&#39;. Business Rule Stack:Actual Start/End Date Validation&#34;,
</span></span><span class="line"><span class="cl">  &#34;changes&#34;: {
</span></span><span class="line"><span class="cl">    &#34;work_end&#34;: {},
</span></span><span class="line"><span class="cl">    &#34;work_start&#34;: {}
</span></span><span class="line"><span class="cl">  }
</span></span><span class="line"><span class="cl">}: no thrown error
</span></span></code></pre></div><h3 id="be-javascript">Be JavaScript</h3>
<h4 id="stringly--typed-values">Stringly  typed values</h4>
<p>WIth <code>GlideRecord</code> there is frequently issues with the type of value returned. For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">gr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">addQuery</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;Abel&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">next</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">first_name</span><span class="p">);</span> <span class="c1">// -&gt; Abel
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">firt_name</span> <span class="o">===</span> <span class="s1">&#39;Abel&#39;</span><span class="p">);</span> <span class="c1">// -&gt; false 🤔
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">first_name</span><span class="p">));</span> <span class="c1">// -&gt; object
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>The reason is that the <code>first_name</code>is a java object. Another example with <code>GlideRecord</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">gr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">gr</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">gr</span><span class="p">.</span><span class="nx">next</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">gr</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// will return &#34;0&#34; or &#34;-1&#34; as string, and it evaluated always as true...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="c1">//doSomething(gr); 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Last example with GlideAgregate</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">taskGa</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideAgregate</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">taskGa</span><span class="p">.</span><span class="nx">addAggregate</span><span class="p">(</span><span class="s1">&#39;COUNT&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">taskGa</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">taskGa</span><span class="p">.</span><span class="nx">next</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">rowCount</span> <span class="o">=</span> <span class="nx">taskGa</span><span class="p">.</span><span class="nx">getAggregate</span><span class="p">(</span><span class="s1">&#39;COUNT&#39;</span><span class="p">);</span> <span class="c1">// -&gt; return a String (&#34;123&#34;)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// With GlideQuery
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">rowCount</span> <span class="o">=</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">).</span><span class="nx">count</span><span class="p">();</span> <span class="c1">// -&gt; return a number (123)
</span></span></span></code></pre></div><p>With <code>GlideQuery</code> all this example are solved: it return a javascript object, where the <code>key</code> is the field name and the <code>value</code> the actual value of the field:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">gr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">whereNotNull</span><span class="p">(</span><span class="s1">&#39;parent&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">selectOne</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">,</span> <span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="s1">&#39;parent.urgency&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">get</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">gr</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* returns
</span></span></span><span class="line"><span class="cl"><span class="cm">{
</span></span></span><span class="line"><span class="cl"><span class="cm">  &#34;description&#34;: null,
</span></span></span><span class="line"><span class="cl"><span class="cm">  &#34;active&#34;: false,
</span></span></span><span class="line"><span class="cl"><span class="cm">  &#34;parent&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="cm">    &#34;urgency&#34;: 3
</span></span></span><span class="line"><span class="cl"><span class="cm">  },
</span></span></span><span class="line"><span class="cl"><span class="cm">  &#34;sys_id&#34;: &#34;801a087adba52200a6a2b31be0b8f520&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><h4 id="be-expressive">Be expressive</h4>
<p>For reading the data, there is Stream, that apply when reading multiple records and Optional, used for a single record.</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>Stream</th>
          <th>Optional</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Returned by</td>
          <td>select()</td>
          <td>SelectOne(), insert(), update()</td>
      </tr>
      <tr>
          <td>Common methods</td>
          <td>map, flatMap, forEach, reduce, some, any</td>
          <td>get, map, isEmpty, isPresent, ifPresent, orElse</td>
      </tr>
      <tr>
          <td>Comments</td>
          <td>is <a href="https://en.wikipedia.org/wiki/Lazy_evaluation">lazy evaluated</a></td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>Here below are code examples that shows some of the methods in action.</p>
<h4 id="example-with-map-and-foreach">Example with map and forEach</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">whereNotNull</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">user</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="nx">user</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">();</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">gs</span><span class="p">.</span><span class="nx">log</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// will return a list of name in upper case
</span></span></span></code></pre></div><h4 id="example-with-some-and-every">Example with some and every</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">hasOnlyShortDescription</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">whereNotNull</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">every</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">task</span><span class="p">.</span><span class="nx">description</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">;</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="c1">// checks that all records match the condition
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">hasLongDescriptions</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">whereNotNull</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">task</span><span class="p">.</span><span class="nx">description</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="mi">1000</span><span class="p">;</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="c1">// checks that at least one record matched the condition
</span></span></span></code></pre></div><h4 id="examples-with-insert-update-delete">Examples with insert, update, delete</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Insert
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    	<span class="nx">active</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    	<span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Sam Meylan&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    	<span class="nx">city</span><span class="o">:</span> <span class="s1">&#39;Geneva&#39;</span>
</span></span><span class="line"><span class="cl">	<span class="p">})</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// delete
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">disableWorkflow</span><span class="p">()</span> <span class="c1">// disable the business rules
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="p">.</span><span class="nx">deleteMultiple</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// update
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;sys_id&#39;</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">update</span><span class="p">({</span><span class="nx">priority</span><span class="o">:</span> <span class="mi">1</span><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&#39;</span> <span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">updateMultiple</span><span class="p">({</span><span class="nx">order</span><span class="o">:</span> <span class="mi">1</span><span class="p">});</span>
</span></span></code></pre></div><h4 id="examples-with-aggregation">Examples with aggregation</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">companyCount</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;core_company&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;city&#39;</span><span class="p">,</span> <span class="s1">&#39;Berlin&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">count</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">maxReopenCount</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="s1">&#39;reopen_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// will return the max count or 0 if there is no
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">groupBy</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">aggregate</span><span class="p">(</span><span class="s1">&#39;sum&#39;</span><span class="p">,</span> <span class="s1">&#39;reassignment_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">having</span><span class="p">(</span><span class="s1">&#39;sum&#39;</span><span class="p">,</span> <span class="s1">&#39;reassignement_count&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">toArray</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* return
</span></span></span><span class="line"><span class="cl"><span class="cm">[
</span></span></span><span class="line"><span class="cl"><span class="cm">  {
</span></span></span><span class="line"><span class="cl"><span class="cm">    &#34;group&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="cm">      &#34;priority&#34;: 1
</span></span></span><span class="line"><span class="cl"><span class="cm">    },
</span></span></span><span class="line"><span class="cl"><span class="cm">    &#34;sum&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="cm">      &#34;reassignment_count&#34;: 11
</span></span></span><span class="line"><span class="cl"><span class="cm">    }
</span></span></span><span class="line"><span class="cl"><span class="cm">  },
</span></span></span><span class="line"><span class="cl"><span class="cm">  {
</span></span></span><span class="line"><span class="cl"><span class="cm">    &#34;group&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="cm">      &#34;priority&#34;: 2
</span></span></span><span class="line"><span class="cl"><span class="cm">    },
</span></span></span><span class="line"><span class="cl"><span class="cm">    &#34;sum&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="cm">      &#34;reassignment_count&#34;: 3
</span></span></span><span class="line"><span class="cl"><span class="cm">    }
</span></span></span><span class="line"><span class="cl"><span class="cm">  },
</span></span></span><span class="line"><span class="cl"><span class="cm">  ...
</span></span></span><span class="line"><span class="cl"><span class="cm">  */</span>
</span></span></code></pre></div><h4 id="flags">Flags</h4>
<p>Flags are additional indicators that can be added to the field name to request thinks like the display (<code>$DISPLAY</code>) value or the currency code (<code>$CURRENCY_CODE</code>).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;company$DISPLAY&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">doSomething</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;core_company&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">selectOne</span><span class="p">(</span><span class="s1">&#39;market_cap&#39;</span><span class="p">,</span> <span class="s1">&#39;market_cap$CURRENCY_CODE&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">get</span><span class="p">()</span>
</span></span></code></pre></div><h4 id="complex-queries">Complex queries</h4>
<p>Complex queries are queries involving OR conditions or nested conditions.</p>
<p>For example with <code>GlideRecord</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">taskGr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">taskGr</span><span class="p">.</span><span class="nx">addQuery</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">addCondition</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">addOrCondition</span><span class="p">(</span><span class="s1">&#39;severity&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span></code></pre></div><p>How will this be evaluated? it is ambiguous and it could be :</p>
<ol>
<li>(active = true AND priority = 1) OR severity = 1</li>
<li><strong>active = true AND (priority = 1 OR severity = 1)</strong></li>
</ol>
<p>The correct answer is the second one. With GlideRecord, OR has priority over AND.</p>
<p>With GlideQuery, the ambiguity is reduced and things are clearer:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// active = true AND (priority = 1 OR severity = 1)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">          <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">.</span><span class="nx">orWhere</span><span class="p">(</span><span class="s1">&#39;severity&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">,</span> <span class="s1">&#39;assgined_to&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">doSomething</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// manager is NULL OR ( title = &#39;Vice President&#39; AND state = &#39;CA&#39;)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">whereNull</span><span class="p">(</span><span class="s1">&#39;manager&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">          <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;title&#39;</span><span class="p">,</span> <span class="s1">&#39;Vice President&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">.</span><span class="nx">orWhere</span><span class="p">(</span><span class="s1">&#39;state&#39;</span><span class="p">,</span> <span class="s1">&#39;CA&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">doSomething</span><span class="p">)</span>
</span></span></code></pre></div><p>The main difference is the use of a GlideQuery inside the GlideQuery. This force the parenthesis explicitly in the query.</p>
<h2 id="performance">performance</h2>
<p>The use of the `GlideQuery&rsquo;  add an overhead of about 4% to 6%, mainly due to the conversions done from java to javascript.</p>
<p>But we need to keep in mind that in many cases we would do this conversions anyway after the query, when using the data retrieved from the database.</p>
<p>Also it force good practices from a performance point of view. For example, when querying for a single record with <code>GlideRecord</code>, we should add <code>.setLimit()</code>but it is often forgotten. <code>GlideQuery</code>uses <code>selectOne()</code> for this purpose.</p>
<p>Also the <code>getRowCount</code>should not be used to count the record, as the underlying query to the database will query all the records. The <code>GlideAggregate</code>with a <code>count</code>shoud be used instead. <code>GlideQuery</code>offers here an easiest way to achieve this with <code>.count()</code>.</p>
<h2 id="immutability-and-reuse">Immutability and reuse</h2>
<p>The <code>GlideQuery</code>is an immutable object. This means that it can be passed to a function and we don&rsquo;t care what the function is doing with it, unlike with <code>GlideRecord</code>.</p>
<p>It allows also to reuse the query and extend it. Here below some examples:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Javascript" data-lang="Javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">highPriorityTasks</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">generateReport</span><span class="p">(</span><span class="nx">highPriorityTasks</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">notifyOwner</span><span class="p">(</span><span class="nx">highPriorityTasks</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">avgReassignmentCount</span> <span class="o">=</span> <span class="nx">highPriorityTasks</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">avg</span><span class="p">(</span><span class="s1">&#39;reassignment_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span></code></pre></div><h2 id="how-to-enable-it-on-your-instance-for-testing">How to enable it on your instance (for testing)</h2>
<p>So now that we went through a lot of explanations, you will probably want to try by yourself. As stated at the beginning, it is (still) not included in a vanilla instance, but it is part of the ITAM plugin.</p>
<p>Luckily, despite being part of the ITAM plugin, it is possible to enable GlideQuery on your instance and play with it.</p>
<p>Do to so, run the following script:</p>
<blockquote>
<p>⚠Try this in your personal instance only. I would not recommend to use this in a productive environment at the moment. It will likely be evolve and will eventually be integrated in Paris or Quebec release.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">pluginArr</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;com.sn_glidequery&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">pluginMgr</span><span class="o">=</span> <span class="k">new</span> <span class="nx">GlideMultiPluginManagerWorker</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">setPluginIds</span><span class="p">(</span><span class="nx">pluginArr</span> <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">setProgressName</span><span class="p">(</span><span class="s2">&#34;Plugin Installer&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">setBackground</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span>
</span></span></code></pre></div><h3 id="checking--the-code">Checking  the code</h3>
<p>Now that is it installed, you can go in the script includes and look for the <code>GlideQuery</code> script include. It is open and you can read all the code. It is quite interesting well documented. It can also gives you some insights about what can be done and how to use it.</p>
<h2 id="cheat-sheet">Cheat Sheet</h2>
<p>There is a <a href="../glidequery-cheat-sheet/">Cheat Sheet</a> available for help you playing around with this functionnality.</p>
<h2 id="references">References</h2>
<ol>
<li>Peter Bell, breakout  <a href="https://events.servicenow.com/widget/servicenow/knowledge2020/myagenda/session/1581555110988001mNP1?sessionId=1581555110988001mNP1">GlideQuery: A modern upgrade to GlideRecord CCB3052</a>, accessed 2020 06 12</li>
<li>Jace Benson, <a href="https://jace.pro/post/2020-04-28-what-is-glidequery/">What is GlideQuery</a>, 2020 04 28</li>
</ol>]]></content:encoded>
    </item>
    
    <item>
      <title>Using remote tables in ServiceNow</title>
      <link>https://www.snow-adventures.com/posts/using-remote-tables-in-servicenow/</link>
      <pubDate>Wed, 10 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/using-remote-tables-in-servicenow/</guid>
      <description>Smoke tests with remote tables functionnality</description>
      <content:encoded><![CDATA[<h2 id="what-are-remote-tables">What are remote tables</h2>
<p>Since the New York release, ServiceNow offers a new functionality called <em>remote tables</em>.</p>
<p>Remote tables allows to query and retrieves data from other systems, via REST/SOAP and use them almost seamlessly in service-now.</p>
<p>The remote table can be used like a standard, local,  table:</p>
<ul>
<li>They can be queried by script;</li>
<li>We can see the records in lists or in forms;</li>
<li>Reports can be run on the data;</li>
<li>They can be used as reference from other tables (both local or remote tables);</li>
<li>They support, like standard tables, sorting, aggregating and filtering like internal tables;</li>
</ul>
<p>The obvious case is to retrieve data from a remote system, but there is nothing that prevent us to also use local tables or a mix of remote and local tables and present them as one remote table. We can also see the remote tables like a kind of enhanced database view, that allows for example to :</p>
<ul>
<li>aggregating data from multiple sources, both local or remote;</li>
<li>Making calculations;</li>
<li>Applying logic and complex conditions;</li>
</ul>
<p>There is also an option to cache the data that has been retrieved for a certain time, to reduce the load and improve performances.</p>
<p>As you can see, Remote tables are a nice feature to use external data in ServiceNow and have them always up to date. It can be use in numerous scenario where external data need to be always up to date and when it is OK to have it read-only in ServiceNow.</p>
<p>In this article, we will play around and try different use of the remote tables. It will of course not cover all the use cases but it will give a good overview of what can be achieved.</p>
<h2 id="the-different-use-cases">The different use cases</h2>
<p>For this test case, we will link an external table to ServiceNow using the remote table functionality.</p>
<p>As a first step, we will link the user table from an ServiceNow instance, using REST. We will include a few fields, including one reference field to Company and see how it react.</p>
<p>Then we will see how to retrieve the Company data in the remote table (like the company name) and see how to include also local data and set custom data in the remote table like calculation result.</p>
<p>Next step will be to use our remote table in a reference field on a local table (like on the incident table) and see what happen</p>
<p>Then we will create a new remote table for companies and see how we can make a reference from a remote table to another table</p>
<p>Finally we will see during all the article what should be done to optimize the query of the remote table, as the default behavior of our setup is to query always all the records.</p>
<p>For the sack of simplicity, both the source table and the remote table are on the same instance. But for make it more realistic (like if we are not querying another ServiceNow instance), we will not rely on the sys_id of the remote user table and we will user the UserId as the key. For the company table, we will use the sys_id, in order to not overcomplicate the example.</p>
<h2 id="creation-the-remote-table">Creation the Remote Table</h2>
<p>Let&rsquo;s start by creating our remote rable.</p>
<p>There are three main steps:</p>
<ul>
<li>Define the table in the dictionary, where we set the table name, the columns and all the standard options for a table;</li>
<li>Create a REST message to connect to the source table we want to query;</li>
<li>Create the related Script Definition that query the source with the REST message and present the data in the Remote Table.</li>
</ul>
<blockquote>
<p>⚠Remote table plugin activation</p>
<p>Before using the Remote tables, check that the corresponding plug-in (com.glide.script.vtable) is activated. If this is not the case, activate it.</p>
</blockquote>
<h3 id="define-the-table-in-the-dictionary">Define the table in the dictionary</h3>
<p>To define the table in the dictionary, go in the menu <em>System Definition - Remote Tables - Tables</em> and click <em>New</em>.</p>
<blockquote>
<p>⚠  there is currently no possibility to create Remote Table from the Studio. You need to create them from the menu and only after this they will appear in the Studio.</p>
</blockquote>
<p>Fill in the name and choose whether or not you want to create a module, and check all the usual options for table creation (roles, etc.).</p>
<p>Then you need to add in the Columns list all the fields that you want on your Remote Table.</p>
<p>For now, we will keep it simple with only the First Name, Last Name, Company, Active, Phone and Email.</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608115856545.png"/> <figcaption>
            Remote User definition
        </figcaption>
</figure>

<blockquote>
<p>ℹ The Sys_id field is automatically created. Note that there is not the other usual systems fields like sys_created_on, sys_update_by, etc.</p>
</blockquote>
<h3 id="create-the-rest-message">Create the REST message</h3>
<p>Let&rsquo;s create a REST message to the user table in our own instance, using the following settings:</p>
<ul>
<li>Endpoint : <a href="https://xxx.service-now.com/api/now/table/sys_user">https://xxx.service-now.com/api/now/table/sys_user</a></li>
<li>Authentication: basic - Create a profile and set your own user/password for example</li>
<li>add an HTTP method: Get</li>
<li>add the HTTP Query parameter (in the HTTP method);</li>
</ul>
<h3 id="create-the-related-script-definition">Create the related script definition</h3>
<p>Now the next step is to create a script definition for our new Remote Table. Go to <em>System Definition - Remote Tables - Definitions</em> and click <em>New</em>.</p>
<p>In table select the table you created before and let&rsquo;s start writing the script that will retrieve the remote records and make them available in the Remote Table.</p>
<blockquote>
<p>ℹ You will notice that there is a huge comment at the beginning of the script: it contains the explanation about how to prepare the script and how to use the APIs. I suggest you keep it in your script for reference, as there is not this information elsewhere in the documentation.</p>
</blockquote>
<p>Now the goal of the script is to add rows to the Remote Table, using <code>v_table.addRow</code>. This function expect an object containing all the values. The name of each property in the object should match the name of the field defined in the Remote Table.</p>
<p>So let&rsquo;s write the following script, where we query using the REST message and then build and add the rows to our Remote Table.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span> <span class="nx">executeQuery</span><span class="p">(</span><span class="nx">v_table</span><span class="p">,</span> <span class="nx">v_query</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">try</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">		<span class="c1">// get the REST message
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">(</span><span class="s1">&#39;x_12270_remote_tab.my users&#39;</span><span class="p">,</span> <span class="s1">&#39;Get&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// execute it
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">message</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// get the response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">responseBody</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">httpStatus</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getStatusCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// if there is an error, log and return
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">haveError</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">v_query</span><span class="p">.</span><span class="nx">setLastErrorMessage</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">getErrorMessage</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">			<span class="nx">gs</span><span class="p">.</span><span class="nx">addErrorMessage</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">getErrorMessage</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// Parse response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">json</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">global</span><span class="p">.</span><span class="nx">JSON</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">responseObj</span> <span class="o">=</span> <span class="nx">json</span><span class="p">.</span><span class="nx">decode</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">resultArr</span> <span class="o">=</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">result</span><span class="p">;</span> <span class="c1">// all the records are contained in an array &#39;result&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">		<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">&lt;</span> <span class="nx">resultArr</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="c1">//build the row
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">row</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// map fields from the result
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="nx">row</span><span class="p">.</span><span class="nx">first_name</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">first_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="nx">row</span><span class="p">.</span><span class="nx">last_name</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">last_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="nx">row</span><span class="p">.</span><span class="nx">active</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">active</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="nx">row</span><span class="p">.</span><span class="nx">email</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">email</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="nx">row</span><span class="p">.</span><span class="nx">phone</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">phone</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="nx">row</span><span class="p">.</span><span class="nx">company</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">company</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// add the row to the remote table
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="nx">v_table</span><span class="p">.</span><span class="nx">addRow</span><span class="p">(</span><span class="nx">row</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">ex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">v_query</span><span class="p">.</span><span class="nx">setLastErrorMessage</span><span class="p">(</span><span class="nx">ex</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">addErrorMessage</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">ex</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="nx">v_table</span><span class="p">,</span> <span class="nx">v_query</span><span class="p">);</span>
</span></span></code></pre></div><p>Now we can test it with the following script (to run in <em>Background script</em>):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">grX_12270RTSRU</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideRecord</span><span class="p">(</span><span class="s1">&#39;x_12270_remote_tab_st_remote_user&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span><span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">next</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s1">&#39;active: &#39;</span> <span class="o">+</span> <span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s1">&#39;company: &#39;</span> <span class="o">+</span> <span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="s1">&#39;company&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s1">&#39;email: &#39;</span> <span class="o">+</span> <span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s1">&#39;first_name: &#39;</span> <span class="o">+</span> <span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s1">&#39;last_name: &#39;</span> <span class="o">+</span> <span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="s1">&#39;last_name&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s1">&#39;phone: &#39;</span> <span class="o">+</span> <span class="nx">grX_12270RTSRU</span><span class="p">.</span><span class="nx">getValue</span><span class="p">(</span><span class="s1">&#39;phone&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Also if we open the list of the table, you should see records in it:</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image20200608132547250.png"/> <figcaption>
            List of Remote Users
        </figcaption>
</figure>

<p>So far so good: we can see the data from the &lsquo;remote&rsquo; table and use it.</p>
<p>However, if we look carefully, we can see that for the company we only have the sys_id. This is because we do not have the display value in the payload. To get a more user friendly information, like the name of the company, we need to query it and use it in the script definition.</p>
<h4 id="getting-the-company-name-instead-of-the-sys_id">Getting the company name instead of the sys_id</h4>
<p>One easy solution that comes to mind to solve this is to query the remote system with another HTTP method in the same REST message as before and get the company name. Let&rsquo;s see how to do this.</p>
<p>First, let&rsquo;s create a new HTTP method (in the existing REST message) for the company table, in a similar way that the one for querying the users, but with this endpoint: <code>/api/now/table/core_company/${id}</code> (and set a name like <em>GetCompany</em> and use it the the script below).</p>
<p>Then let&rsquo;s create a function <code>getRemoteCompanyName</code> to retrieve the remote company and get the name.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getRemoteCompanyName</span> <span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// get the REST message
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">(</span><span class="s1">&#39;x_12270_remote_tab.my users&#39;</span><span class="p">,</span> <span class="s1">&#39;GetCompany&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// set the id of the company we want to retrive
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">message</span><span class="p">.</span><span class="nx">setStringParameter</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// execute it
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">message</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// get the response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kd">var</span> <span class="nx">responseBody</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nx">httpStatus</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getStatusCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// if there is not error, continue
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">response</span><span class="p">.</span><span class="nx">haveError</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// Parse response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="kd">var</span> <span class="nx">responseObj</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">global</span><span class="p">.</span><span class="nx">JSON</span><span class="p">().</span><span class="nx">decode</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="kd">var</span> <span class="nx">resultObj</span> <span class="o">=</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// check if the reuslt if ok and return the name
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">if</span> <span class="p">(</span><span class="nx">resultObj</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="nx">resultObj</span><span class="p">.</span><span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// default empty string
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">return</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">ex</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nx">gs</span><span class="p">.</span><span class="nx">addErrorMessage</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">ex</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And replace the mapping line with this one:</p>
<pre tabindex="0"><code class="language-javasc" data-lang="javasc">row.company = getRemoteCompanyName(resultArr[i].company.value);
</code></pre><p>If we try it, we now we get the company name, but it pretty slow. The reason is that our script need to query the remote system for each user.</p>
<p>We will see later in this post of the solve this issue.  If performances are too bad, for now just comment the mapping on the company.</p>
<h2 id="adding-calculation-and-local-data-to-the-remote-table">Adding calculation and local data to the remote table</h2>
<p>Now let&rsquo;s see how we can add calculated data to the rows in the remote table and how we can use local data as well.</p>
<p>The calculated data would be simply to add a prefix to the phone number coming from the remote instance.</p>
<p>And local data would be looking incidents where the caller email matches the remote user email and give a count of how many incidents are found.</p>
<p>Both addition to the remote table are quite straightforward: we just need to add the required data in the row.</p>
<h4 id="add-prefix-to-the-phone-number">Add prefix to the phone number</h4>
<p>Simply amend the script to add the prefix to the phone number, like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// add prefix to phone
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">phone</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">phone</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">phone</span> <span class="o">!=</span> <span class="s2">&#34;&#34;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="nx">phone</span> <span class="o">=</span> <span class="s2">&#34;+123 - &#34;</span> <span class="o">+</span> <span class="nx">phone</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">row</span><span class="p">.</span><span class="nx">phone</span> <span class="o">=</span> <span class="nx">phone</span><span class="p">;</span>
</span></span></code></pre></div><p>Now the users that have a phone number will have the prefix added in front</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200609121927495.png"/> <figcaption>
            phone numbers are now prefixed
        </figcaption>
</figure>

<h4 id="add-an-incident-counter">Add an incident counter</h4>
<p>This requirement is a bit more complicated. First of all let&rsquo;s create a new field *incident count&quot; on the Remote User table.</p>
<p>To do this, go in the menu <em>System Definition - Remote Tables - Tables</em>, select the Remote User table and add a new field.</p>
<p>Then in the script definition, let&rsquo;s create a function <code>getIncidentCount</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getIncidentCount</span><span class="p">(</span><span class="nx">email</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// get the incident count where caller email match the given email
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kd">var</span> <span class="nx">incidentGr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideAggregate</span><span class="p">(</span><span class="s2">&#34;incident&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">incidentGr</span><span class="p">.</span><span class="nx">addQuery</span><span class="p">(</span><span class="s2">&#34;caller_id.email&#34;</span><span class="p">,</span> <span class="nx">email</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">incidentGr</span><span class="p">.</span><span class="nx">addAggregate</span><span class="p">(</span><span class="s1">&#39;COUNT&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">incidentGr</span><span class="p">.</span><span class="nx">query</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">incidentGr</span><span class="p">.</span><span class="nx">next</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nx">incidentGr</span><span class="p">.</span><span class="nx">getAggregate</span><span class="p">(</span><span class="s2">&#34;COUNT&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">ex</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nx">gs</span><span class="p">.</span><span class="nx">addErrorMessage</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">ex</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>And add the result of the function into the new field on the row:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// add incident count 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">row</span><span class="p">.</span><span class="nx">incident_count</span> <span class="o">=</span> <span class="nx">getIncidentCount</span><span class="p">(</span><span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">email</span><span class="p">);</span>
</span></span></code></pre></div><p>Now the remote user have the incident counter filled:</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200609124029773.png"/> <figcaption>
            Incident counter is filled
        </figcaption>
</figure>

<h2 id="referencing-a-remote-table-from-a-local-table">Referencing a remote table from a local table</h2>
<p>Now that we have the Remote User table defined and working, let&rsquo;s use it in other tables. For example, let&rsquo;s add a new field on the incident table, referencing the Remote User table.</p>
<p>First, let&rsquo;s create a new reference field on the incident table, with reference to the Remote User table.</p>
<p>Then let&rsquo;s try to use it: open the pop-up related list and choose a random Remote User. Before doing so, you will need to edit the reference list layout to add some meaningful fields, like First Name, Last Name and Email.</p>
<p>What happen after selecting the record?  The field Remote User is still empty&hellip;</p>
<p>Why is this? The reason is simple: there is no sys_id defined on our remote table. This means that the reference field don&rsquo;t know how to related to the correct row in the remote table, as sys_id is empty for all the rows of the remote table.</p>
<p>To solve this, we need to populate the sys_id of our rows. This need to be done, as you probably guess,  in the definition script.</p>
<p>We could take the remote system sys_id, but let&rsquo;s pretend we are not retrieving the records from another service-now instance and that we do not have a sys_id coming in. Let&rsquo;s use instead the user ID (<em>user_name</em>), with a prefix &lsquo;remote_&rsquo; added.</p>
<p>Let add this line to our script:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">row</span><span class="p">.</span><span class="nx">sys_id</span> <span class="o">=</span> <span class="s1">&#39;remote_&#39;</span> <span class="o">+</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">user_name</span><span class="p">;</span>
</span></span></code></pre></div><p>If we now go back in the incident and try again to select a Remote User, the value is set in the field and if we save the incident, it remains. We can even preview the record like with a local table (but read-only).</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608142639529.png"/> <figcaption>
            Result after fixing the sys_id
        </figcaption>
</figure>

<p>Technically, it stores what we have set as a sys_id into the reference field:</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608144816731.png"/> <figcaption>
            XML view of the field
        </figcaption>
</figure>

<h3 id="change-the-display-value-of-the-remote-table">Change the display value of the remote table</h3>
<p>It would be nicer if we can have something else that the sys_id set as a display value. Is this possible? Yes, of course: just go in the table definition and set the field you want to have as a display value.</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608142842844.png"/> <figcaption>
            Set a display value...
        </figcaption>
</figure>

<p>Back in the incident, we now have the First Name as the display value:</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608142939053.png"/> <figcaption>
            ... and enjoy a user friendly value
        </figcaption>
</figure>

<h2 id="query-optimization">Query optimization</h2>
<p>Each time we go in the Remote Table, or we open a specific record, or use it like in the incident, the Remote Table queries the remote system and retrieve all the existing records. This is not optimal and could lead to poor response time.</p>
<p>We could of course enable the caching, but first let&rsquo;s try to optimize the queries.</p>
<p>First let&rsquo;s make a check to know how many records are coming in each time we query the Remote Table:. Add the following the the Remote Table definition script:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">gs</span><span class="p">.</span><span class="nx">addInfoMessage</span><span class="p">(</span><span class="s2">&#34;querying remote users return &#34;</span><span class="o">+</span>  <span class="nx">resultArr</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span><span class="sb">`
</span></span></span></code></pre></div><p>If we now refresh the incident, we see that we query a lot of users, even if we want to display only one record.</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608143854825.png"/> <figcaption>
            it queries always all the records...
        </figcaption>
</figure>

<h3 id="getting-a-single-record">Getting a single record</h3>
<p>To optimye the query, we need somehow to get only the record that is interesting us.</p>
<p>The query helper method <code>v_query.isGet()</code> indicate if the query is a <em>get</em> and that only one record is expected.</p>
<p>We can then query the remote system with a different API call, using this endpoint <code>/api/now/table/sys_user/${id}</code>. The id will be provided by <code>v_query.getSysId()</code>.</p>
<p>That would work like a charm if we didn&rsquo;t decided to use a custom sys_id  (&ldquo;remote_&rdquo; + user_name).</p>
<p>To overcome this, we need instead to use the same endpoint and build a query using the <em>user_name</em>.  Luckily, <code>v_query.getSysId()</code> returns the sys_id stored in the reference field (or coming from a <em>get</em> from <em>GlideRecord</em>), so we can use it in our query.</p>
<p>Let&rsquo;s add the following code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// handle the get case
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span> <span class="p">(</span><span class="nx">v_query</span><span class="p">.</span><span class="nx">isGet</span><span class="p">()){</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// get the sys_id
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">var</span> <span class="nx">sys_id</span> <span class="o">=</span> <span class="nx">v_query</span><span class="p">.</span><span class="nx">getSysId</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// remove the remote_ from sys_id
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">sys_id</span> <span class="o">=</span> <span class="nx">sys_id</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s2">&#34;remote_&#34;</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">    <span class="c1">// build the query
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">message</span><span class="p">.</span><span class="nx">setQueryParameter</span><span class="p">(</span><span class="s2">&#34;sysparm_query&#34;</span><span class="p">,</span> <span class="s2">&#34;user_name=&#34;</span> <span class="o">+</span> <span class="nx">sys_id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>and try to refresh the incident:</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608150036336.png"/> <figcaption>
            and now it queries only the requested record
        </figcaption>
</figure>

<p>Our query is now retrieving only the record that is needed.</p>
<h3 id="getting-onl-y-the-records-matching-a-filter">Getting onl y the records matching a filter</h3>
<p>There are multiple cases where we filter the records, for example in a list, in a reference qualifier, etc.</p>
<p>Without anything in place, the remote table don&rsquo;t care about the filer and always triggers a full query to the remote table.</p>
<p>But we can restrict the query to the remote system according the filter set in the query to the remote table.</p>
<h4 id="restrict-the-query-to-the-remote-system">Restrict the query to the remote system</h4>
<p>If we go to the Remote User table and filter, we can see that anyway the Remote Table query all the records from the remote system</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608150502046.png"/> <figcaption>
            when filtering, it queries anyway all the records...
        </figcaption>
</figure>

<p>To avoid this, we need to add a filter on the outgoing REST message.</p>
<p>We can know about the query with the helper function <code>v_query.getEncodedQuery()</code>.</p>
<p>We can also get rid of the part with the <code>isGet</code>that we put in place before, because the encoded query contains in this case <code>'sys_id=xxx'</code>.</p>
<blockquote>
<p>⚠ Of course, depending the backend system, it will probably not be possible to simply use the encoded query. An ad-hoc query would need to be built. There are two functions that can help achieving this, if needed: <code>v_query.getCondition()</code> and <code>v_query.getParameter()</code>.</p>
</blockquote>
<p>For the sys_id, here we need something to put a special handling in place to basically to parse the encoded query, replace <code>sys_id</code>with the name of the field we want (<em>user_name</em>) and remove the prefix <em>remote_</em>.  For more clarity this sys_id handling it is placed in a separate function <code>adaptSysIdQuery()</code>.</p>
<p>So we can modify the script as follow:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// get the encoded query
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">query</span> <span class="o">=</span> <span class="nx">v_query</span><span class="p">.</span><span class="nx">getEncodedQuery</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// set the query, if not empty
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span> <span class="p">(</span><span class="nx">query</span> <span class="o">!=</span> <span class="s2">&#34;&#34;</span> <span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="nx">message</span><span class="p">.</span><span class="nx">setQueryParameter</span><span class="p">(</span><span class="s2">&#34;sysparm_query&#34;</span><span class="p">,</span> <span class="nx">adaptSysIdQuery</span> <span class="p">(</span><span class="nx">query</span><span class="p">,</span> <span class="s2">&#34;user_name&#34;</span><span class="p">,</span> <span class="s2">&#34;remote_&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Function to adapt the sysid for the REST query - replace sys_id with the field name and remove the prefix
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">adaptSysIdQuery</span> <span class="p">(</span><span class="nx">query</span><span class="p">,</span> <span class="nx">idField</span><span class="p">,</span> <span class="nx">prefix</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// if there is no sys_id in the query, return
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">if</span> <span class="p">(</span><span class="nx">query</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">&#39;sys_id&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="nx">query</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// split each condition
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">queryArr</span> <span class="o">=</span> <span class="nx">query</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;^&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">queryArr</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="kd">var</span> <span class="nx">elementStr</span> <span class="o">=</span> <span class="nx">queryArr</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">			<span class="c1">// split each term of the condition
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">elementArr</span> <span class="o">=</span> <span class="nx">elementStr</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s2">&#34;=&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="p">(</span><span class="nx">elementArr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;sys_id&#34;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// replace sys_id by the field name
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="nx">elementArr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">idField</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// remove the prefix
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="nx">elementArr</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">elementArr</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="nx">prefix</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">				<span class="c1">// reassemble elementArr and set back in queryArr
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>				<span class="nx">queryArr</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">elementArr</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s2">&#34;=&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// reassemble query and return
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="nx">query</span> <span class="o">=</span> <span class="nx">queryArr</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;^&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nx">query</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span></code></pre></div><p>Now back on the list, if we refresh we can see that we are querying only the record we need from the list.</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608154308360.png"/> <figcaption>
            and now it queries the records according the filter
        </figcaption>
</figure>

<h2 id="references-between-remote-tables">References between remote tables</h2>
<p>Remember above? With the company field on the Remote User table, we added a function that retrieve the company information from the remote instance and set it in the row.</p>
<p>What about, instead, creating a new remote table for the company and make the reference work between the existing Remote User table?</p>
<h3 id="create-the-remote-company-table">Create the Remote Company table</h3>
<p>To do this, create a Remote Company remote table, in a similar way that for the incident</p>
<p>Add the fields you need on that table. At the moment we really only need the field <em>name</em>. As you are in the dictionnary, set this field <em>name</em> as the display value.</p>
<h3 id="create-a-http-method">Create a HTTP method</h3>
<p>Create a new HTTP method (in the existing REST message) for the company table, in a similar way that the previous for querying the company, but with this endpoint: <code>/api/now/table/core_company</code> (and set a name like <em>GetCompanies</em> and use it the the script below). The difference with the previous endpoint is that now we want to be able to query all the companies, not just only a specific company, hence the use of a different endpoint.</p>
<h3 id="create-the-script-definition">Create the script definition</h3>
<p>Then create the related script definition for the Remote Company table and use the script below. Note that, not like with incident, we are now using the remote record sys_id as a sys_id.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span> <span class="nx">executeQuery</span><span class="p">(</span><span class="nx">v_table</span><span class="p">,</span> <span class="nx">v_query</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">try</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// get the REST message
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">(</span><span class="s1">&#39;x_12270_remote_tab.my users&#39;</span><span class="p">,</span> <span class="s1">&#39;GetCompanies&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// get the encoded query
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">query</span> <span class="o">=</span> <span class="nx">v_query</span><span class="p">.</span><span class="nx">getEncodedQuery</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// set the query if not empty
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">if</span> <span class="p">(</span><span class="nx">query</span> <span class="o">!=</span> <span class="s2">&#34;&#34;</span> <span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="nx">message</span><span class="p">.</span><span class="nx">setQueryParameter</span><span class="p">(</span><span class="s2">&#34;sysparm_query&#34;</span><span class="p">,</span>  <span class="nx">query</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// execute it
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">message</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// get the response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">responseBody</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">httpStatus</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getStatusCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// if there is an error, log and return
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">haveError</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">v_query</span><span class="p">.</span><span class="nx">setLastErrorMessage</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">getErrorMessage</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">			<span class="nx">gs</span><span class="p">.</span><span class="nx">addErrorMessage</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">getErrorMessage</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="c1">// Parse response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="kd">var</span> <span class="nx">json</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">global</span><span class="p">.</span><span class="nx">JSON</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">responseObj</span> <span class="o">=</span> <span class="nx">json</span><span class="p">.</span><span class="nx">decode</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">resultArr</span> <span class="o">=</span> <span class="nx">responseObj</span><span class="p">.</span><span class="nx">result</span><span class="p">;</span> <span class="c1">// all the records are contained in an array &#39;result&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        
</span></span><span class="line"><span class="cl">		<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">&lt;</span> <span class="nx">resultArr</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="c1">//build the row
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="kd">var</span> <span class="nx">row</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// map fields from the result
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="nx">row</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// build sys_id
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="nx">row</span><span class="p">.</span><span class="nx">sys_id</span> <span class="o">=</span> <span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">sys_id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="c1">// add the row to the remote table
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>			<span class="nx">v_table</span><span class="p">.</span><span class="nx">addRow</span><span class="p">(</span><span class="nx">row</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">ex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">v_query</span><span class="p">.</span><span class="nx">setLastErrorMessage</span><span class="p">(</span><span class="nx">ex</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">addErrorMessage</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">ex</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="nx">v_table</span><span class="p">,</span> <span class="nx">v_query</span><span class="p">);</span>
</span></span></code></pre></div><p>Now we can try the Remote Company table and check that we get all the records.</p>
<h3 id="adapt-the--remote-user-table">Adapt the  Remote User table</h3>
<p>Let&rsquo;s do now the required adaptation on the Remote User table.</p>
<p>First, go in the dictionary and change the type of the field <em>company</em> to Reference and make it reference to the new Remote Company table.</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608164320222.png"/> <figcaption>
            changing the company to reference
        </figcaption>
</figure>

<p>Then adapt the script definition of the Remote User table to set the value of the field <em>company</em> to the sys_id of the company coming in the payload:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">row</span><span class="p">.</span><span class="nx">company</span> <span class="o">=</span><span class="nx">resultArr</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">company</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span></span></code></pre></div><p>Now let&rsquo;s try to open a Remote User and see if it works:</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608164111357.png"/> <figcaption>
            It works from Remote User
        </figcaption>
</figure>

<p>It looks fine. Also from the list:</p>
<figure>
    <img loading="lazy" src="/img/remotetable/image-20200608164130814.png"/> <figcaption>
            ... from the list
        </figcaption>
</figure>

<h2 id="conclusion">Conclusion</h2>
<p>We cover quite some use cases in the examples above. The main idea was to discover this remote tables functionality and to play a bit with them.</p>
<p>The key take away is that remote table are a powerful feature to add in out toolbox. It can be used to help in numerous use case, either using remote data or calculating data on local tables.</p>
<p>Please leave you comments or questions below.</p>
<h2 id="references">References</h2>
<ol>
<li>ServiceNow documentation, <a href="https://docs.servicenow.com/bundle/orlando-servicenow-platform/page/administer/remote-tables/concept/remote-tables.html">Retrieving external data using remote tables and scripts</a>, accessed 2020 06 09</li>
<li>Chuck Tomasi, <a href="https://www.youtube.com/watch?v=gw1Lzuy4bZk">NOWCommunity Live Stream - Topical Deep Dive - Remote tables</a>, broadcasted 2020 05 04</li>
</ol>]]></content:encoded>
    </item>
    
    <item>
      <title>GlideQuery Cheat Sheet</title>
      <link>https://www.snow-adventures.com/posts/glidequery-cheat-sheet/</link>
      <pubDate>Tue, 09 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/glidequery-cheat-sheet/</guid>
      <description>an attempt to document GlideQuery functions and methods</description>
      <content:encoded><![CDATA[<p>This is a draft Cheat Sheet for the <code>GlideQuery</code>. Please see this <a href="../overview-of-glidequery/">post</a> for a detailled introduction.</p>
<p>This cheat sheet was build with elements gathered from presentations and blog posts and also from reading the script include. It may not be accurate, might evolve and all comments and corrections are welcome !</p>
<h2 id="invoking-glidequery">invoking <code>GlideQuery</code></h2>
<p>In a similar way that <code>GlideRecord</code>, the table name is passed as a parameter:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">myTable</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;table_name&#39;</span><span class="p">);</span>
</span></span></code></pre></div><h2 id="cheat-sheet">Cheat sheet</h2>
<h3 id="selections-insert-update">Selections, insert, update</h3>
<h4 id="get">get()</h4>
<p>Returns a single record by querying primary key <code>key</code>.</p>
<h5 id="parameters">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>key</td>
          <td>(sys_id)</td>
      </tr>
      <tr>
          <td>Array</td>
          <td>selectedFields</td>
          <td>Additional fields to return in result</td>
      </tr>
  </tbody>
</table>
<h5 id="example">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">     <span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;5137153cc611227c000bbd1bd8cd2005&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;last_name&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">     <span class="p">.</span><span class="nx">orElse</span><span class="p">({</span> <span class="nx">first_name</span><span class="o">:</span> <span class="s1">&#39;Default&#39;</span><span class="p">,</span> <span class="nx">last_name</span><span class="o">:</span> <span class="s1">&#39;User&#39;</span> <span class="p">});</span>
</span></span></code></pre></div><hr>
<h4 id="getby">getBy()</h4>
<p>Returns a single record, using <code>keyValues</code> as a set of key-values to query by.
getBy assumes the &lsquo;=&rsquo; operator for each key-value.</p>
<h5 id="parameters-1">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Object</td>
          <td>keyValues</td>
          <td>Object where the keys are the name of the fields, and the values are the values.</td>
      </tr>
      <tr>
          <td>Array</td>
          <td>selectedFields</td>
          <td>Additional fields to return in result</td>
      </tr>
  </tbody>
</table>
<h5 id="example-1">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">getBy</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">first_name</span><span class="o">:</span> <span class="s1">&#39;Fred&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">last_name</span><span class="o">:</span> <span class="s1">&#39;Luddy&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span> <span class="p">[</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;last_name&#39;</span><span class="p">,</span> <span class="s1">&#39;city&#39;</span><span class="p">,</span> <span class="s1">&#39;active&#39;</span><span class="p">])</span> <span class="c1">// select first_name, last_name, city, active
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">.</span><span class="nx">orElse</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">         <span class="nx">first_name</span><span class="o">:</span> <span class="s1">&#39;Nobody&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">last_name</span><span class="o">:</span> <span class="s1">&#39;Found&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">city</span><span class="o">:</span> <span class="s1">&#39;Nowhere&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">active</span><span class="o">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span></code></pre></div><hr>
<h4 id="insert">insert()</h4>
<p>Inserts a single record</p>
<h5 id="parameters-2">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Object</td>
          <td>keyValues</td>
          <td>Object containing key-values to insert into table</td>
      </tr>
      <tr>
          <td>Array</td>
          <td>selectedFields</td>
          <td>Fields to return in result Optional</td>
      </tr>
  </tbody>
</table>
<h5 id="example-2">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">         <span class="nx">active</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">         <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Sam Meylan&#39;</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">        <span class="nx">city</span><span class="o">:</span> <span class="s1">&#39;Geneva&#39;</span> 
</span></span><span class="line"><span class="cl">    <span class="p">})</span> 
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">get</span><span class="p">();</span>
</span></span></code></pre></div><hr>
<h4 id="insertorupdate">insertOrUpdate()</h4>
<p>Updates an existing record (just like update), however instead of requiring
where calls, it uses the primary key(s) in the recordValues object passed
in. If the primary key(s) isn&rsquo;t there, insertOrUpdate will insert a new
record instead. Returns an Optional of the newly created/updated record.
Often useful when you want to want to ensure a record exists and has the
correct values, as you don&rsquo;t need to check for the record&rsquo;s existence beforehand.</p>
<h5 id="parameters-3">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Object</td>
          <td>changes</td>
          <td>Object containing key-values to update/insert into table</td>
      </tr>
      <tr>
          <td>Array</td>
          <td>selectedFields</td>
          <td>Fields to return in result Optional</td>
      </tr>
  </tbody>
</table>
<h5 id="example-3">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// insert a new record
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">insertOrUpdate</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">first_name</span><span class="o">:</span> <span class="s1">&#39;George&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">last_name</span><span class="o">:</span> <span class="s1">&#39;Griffey&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// update existing record
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">insertOrUpdate</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">sys_id</span><span class="o">:</span> <span class="s1">&#39;2d0efd6c73662300bb513198caf6a72e&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">first_name</span><span class="o">:</span> <span class="s1">&#39;George&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">last_name</span><span class="o">:</span> <span class="s1">&#39;Griffey&#39;</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="update">update()</h4>
<p>Updates an existing record. Requires a where call, specifying all existing primary keys (usually sys_id). Returns an Optional of the newly-updated record.</p>
<h5 id="parameters-4">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Object</td>
          <td>changes</td>
          <td>Object containing key-values to update/insert into table</td>
      </tr>
      <tr>
          <td>Array</td>
          <td>selectedFields</td>
          <td>Fields to return in result Optional</td>
      </tr>
  </tbody>
</table>
<h5 id="example-4">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;sys_id&#39;</span><span class="p">,</span> <span class="nx">userId</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">update</span><span class="p">({</span> <span class="nx">city</span><span class="o">:</span> <span class="s1">&#39;Los Angeles&#39;</span> <span class="p">});</span>
</span></span></code></pre></div><hr>
<h4 id="updatemultiple">updateMultiple()</h4>
<p>Updates all records in the table (specified by preceding where clause with the values contained in the changes object. Returns # of records updated.</p>
<h5 id="parameters-5">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Object</td>
          <td>changes</td>
          <td>Object containing key-values to update/insert into table</td>
      </tr>
  </tbody>
</table>
<h5 id="example-5">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">false</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;last_name&#39;</span><span class="p">,</span> <span class="s1">&#39;Griffey&#39;</span><span class="p">)</span><span class="o">&lt;</span><span class="nx">r</span><span class="o">&gt;</span>    <span class="p">.</span><span class="nx">updateMultiple</span><span class="p">({</span> <span class="nx">active</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span></code></pre></div><hr>
<h4 id="select">select()</h4>
<p>Specifies which fields to return and returns a Stream containing the results of the query. Note that records aren&rsquo;t actually read from the database until a terminal Stream method is called (such as reduce() or toArray()). The Stream is intended for reading multiple records in a similar fashion to Java&rsquo;s Stream class.</p>
<h5 id="parameters-6">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>&hellip;String</td>
          <td>fields</td>
          <td>Fields to select</td>
      </tr>
  </tbody>
</table>
<h5 id="example-6">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">stream</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;last_name&#39;</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="selectone">selectOne()</h4>
<p>Similar to <code>select()</code>, however only returns an Optional which may contain a single record. This is more efficient than <code>select()</code> if you only need one record, or want to test if a record exists.</p>
<h5 id="parameters-7">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>&hellip;String</td>
          <td>fields</td>
          <td>Fields to select</td>
      </tr>
  </tbody>
</table>
<h5 id="example-7">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;zip&#39;</span><span class="p">,</span> <span class="s1">&#39;12345&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">whereNotNull</span><span class="p">(</span><span class="s1">&#39;last_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">selectOne</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;last_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">get</span><span class="p">();</span>
</span></span></code></pre></div><hr>
<h4 id="del">Del()</h4>
<p>Deletes all records in the table specified by preceding where clauses</p>
<h5 id="example-8">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;last_name&#39;</span><span class="p">,</span> <span class="s1">&#39;Jeter&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">del</span><span class="p">();</span>
</span></span></code></pre></div><h3 id="conditions">Conditions</h3>
<h4 id="where">where()</h4>
<p>Returns a new GlideQuery containing where clause</p>
<h5 id="parameters-8">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>Field related to the where clause</td>
      </tr>
  </tbody>
</table>
<h5 id="example-9">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;last_login&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;2016-04-15&#39;</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="wherenotnull">whereNotNull()</h4>
<p>Returns a new GlideQuery containing NOT NULL clause</p>
<h5 id="parameters-9">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>Field related to the clause</td>
      </tr>
  </tbody>
</table>
<h5 id="example-10">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">whereNotNull</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">)</span>
</span></span></code></pre></div><hr>
<h4 id="wherenull">whereNull()</h4>
<p>Returns a new GlideQuery containing WHERE NULL clause</p>
<h5 id="parameters-10">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>Field related to the clause</td>
      </tr>
  </tbody>
</table>
<h5 id="example-11">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">whereNull</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="aggregations">Aggregations</h3>
<h4 id="avg">avg()</h4>
<p>Returns the aggregate average of a given numeric field</p>
<h5 id="parameters-11">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>Numeric field</td>
      </tr>
  </tbody>
</table>
<h5 id="example-12">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">faults</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;cmdb_ci&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">avg</span><span class="p">(</span><span class="s1">&#39;fault_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="max">max()</h4>
<p>Returns the aggregate minimum of a given field</p>
<h5 id="parameters-12">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>field</td>
      </tr>
  </tbody>
</table>
<h5 id="example-13">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">faults</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;cmdb_ci&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="min">min()</h4>
<p>Returns the aggregate maximum of a given field</p>
<h5 id="parameters-13">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>field</td>
      </tr>
  </tbody>
</table>
<h5 id="example-14">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">faults</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;cmdb_ci&#39;</span><span class="p">)</span>    
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">min</span><span class="p">(</span><span class="s1">&#39;sys_mod_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="sum">sum()</h4>
<p>Returns the aggregate sum of a given numeric field</p>
<h5 id="parameters-14">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>Numeric field</td>
      </tr>
  </tbody>
</table>
<h5 id="example-15">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">totalFaults</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;cmdb_ci&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">sum</span><span class="p">(</span><span class="s1">&#39;fault_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orElse</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="count">count()</h4>
<p>Returns the row count of records matching the query</p>
<h5 id="example-16">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">userCount</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">count</span><span class="p">();</span>
</span></span></code></pre></div><hr>
<h4 id="groupby">groupBy()</h4>
<p>Groups query results. Used with <code>aggregate()</code></p>
<h5 id="example-17">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">aggregate</span><span class="p">(</span><span class="s1">&#39;count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">groupBy</span><span class="p">(</span><span class="s1">&#39;contact_type&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">select</span><span class="p">();</span>
</span></span></code></pre></div><hr>
<h4 id="aggregate">aggregate()</h4>
<p>Aggregates a field using an aggregate function. Used to buildqueries which aggregate against multiple fields and/or multipleaggregate functions. If you only need to aggregate against one field with one function, and you don&rsquo;t need to use groupBy(), then use one of the terminal functions instead:
<code>avg()</code>
<code>min()</code>
<code>max()</code>
<code>count()</code></p>
<h5 id="parameters-15">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>aggregateType</td>
          <td>Aggregate type (&lsquo;sum&rsquo;, &lsquo;avg&rsquo;, &lsquo;min&rsquo;, &lsquo;max&rsquo;, or &lsquo;count&rsquo;)</td>
      </tr>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>Field to aggregate</td>
      </tr>
  </tbody>
</table>
<h5 id="example-18">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">aggregate</span><span class="p">(</span><span class="s1">&#39;avg&#39;</span><span class="p">,</span> <span class="s1">&#39;reassignment_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">groupBy</span><span class="p">(</span><span class="s1">&#39;contact_type&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">select</span><span class="p">();</span>
</span></span></code></pre></div><hr>
<h4 id="having">having()</h4>
<p>Filters aggregate groups. Used with <code>aggregate()</code> and <code>groupBy</code>.</p>
<h5 id="parameters-16">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>String</td>
          <td>aggregateType</td>
          <td>Aggregate type (&lsquo;sum&rsquo;, &lsquo;avg&rsquo;, &lsquo;min&rsquo;, &lsquo;max&rsquo;, or &lsquo;count&rsquo;)</td>
      </tr>
      <tr>
          <td>String</td>
          <td>field</td>
          <td>Field to aggregate</td>
      </tr>
      <tr>
          <td>String</td>
          <td>operator</td>
          <td>Only numeric operators allowed: &lsquo;&gt;&rsquo;, &lsquo;&lt;&rsquo;, &lsquo;&gt;=&rsquo;, &lsquo;&lt;=&rsquo;, &lsquo;=&rsquo;, and &lsquo;!=&rsquo;</td>
      </tr>
      <tr>
          <td>number</td>
          <td>value</td>
          <td></td>
      </tr>
  </tbody>
</table>
<h5 id="example-19">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="o">*</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">,</span> <span class="nx">description</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">groupBy</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">aggregate</span><span class="p">(</span><span class="s1">&#39;sum&#39;</span><span class="p">,</span> <span class="s1">&#39;reassignment_count&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">having</span><span class="p">(</span><span class="s1">&#39;sum&#39;</span><span class="p">,</span> <span class="s1">&#39;reassignment_count&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">select</span><span class="p">()</span>
</span></span></code></pre></div><h3 id="miscellanious">Miscellanious</h3>
<h4 id="disableautosysfields">disableAutoSysFields()</h4>
<p>Returns a GlideQuery which does not update sys fields such as sys_created_on, sys_updated_on, and sys_mod_count. This is the equivalent of using autoSysFields(false) with GlideRecord.</p>
<h5 id="example-20">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">disableAutoSysFields</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">insert</span><span class="p">({</span> <span class="nx">description</span><span class="o">:</span> <span class="s1">&#39;example&#39;</span><span class="p">,</span> <span class="nx">priority</span><span class="o">:</span> <span class="mi">1</span> <span class="p">});</span>
</span></span></code></pre></div><hr>
<h4 id="forceupdate">forceUpdate()</h4>
<p>Returns a GlideQuery which forces an update even when no changes are made. Useful when you want to force a business rule to execute.</p>
<h5 id="example-21">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;task&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">forceUpdate</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s1">&#39;sys_id&#39;</span><span class="p">,</span> <span class="nx">taskId</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">update</span><span class="p">()</span>
</span></span></code></pre></div><hr>
<h4 id="orderby">orderBy()</h4>
<p>Returns a GlideQuery which specifies that the records should be returned in ascending order by a given field.</p>
<h5 id="example-22">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">query</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orderBy</span><span class="p">(</span><span class="s1">&#39;number&#39;</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="orderbydesc">orderByDesc()</h4>
<p>Returns a GlideQuery which specifies that the records should be returned in descending order by a given field. Can be used with aggregate queries</p>
<h5 id="example-23">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">query</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orderByDesc</span><span class="p">(</span><span class="s1">&#39;number&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">aggregate</span><span class="p">(</span><span class="s1">&#39;sum&#39;</span><span class="p">,</span> <span class="s1">&#39;child_incidents&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">groupBy</span><span class="p">(</span><span class="s1">&#39;category&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orderByDesc</span><span class="p">(</span><span class="s1">&#39;sum&#39;</span><span class="p">,</span> <span class="s1">&#39;child_incidents&#39;</span><span class="p">)</span>
</span></span></code></pre></div><hr>
<h4 id="limit">limit()</h4>
<p>Returns a GlideQuery which limits the number of records returned.</p>
<h5 id="parameters-17">Parameters</h5>
<table>
  <thead>
      <tr>
          <th>Type</th>
          <th>Name</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>[number</td>
          <td>limit max number of records to return</td>
          <td></td>
      </tr>
  </tbody>
</table>
<h5 id="example-24">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">incidents</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;incident&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">limit</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="s1">&#39;description&#39;</span><span class="p">);</span>
</span></span></code></pre></div><hr>
<h4 id="withacls">withAcls()</h4>
<p>By default GlideQuery uses GlideRecord for database interactions. By calling withAcls() GlideQuery will use GlideRecordSecure, which honors ACLs.</p>
<h5 id="example-25">Example</h5>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">users</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlideQuery</span><span class="p">(</span><span class="s1">&#39;sys_user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">withAcls</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">limit</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">orderByDesc</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">select</span><span class="p">(</span><span class="s1">&#39;first_name&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">toArray</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
</span></span></code></pre></div><hr>
]]></content:encoded>
    </item>
    
    <item>
      <title>High order function in script include, accessing the context (this)</title>
      <link>https://www.snow-adventures.com/posts/high-order-function-in-script-include-accessing-the-context-this/</link>
      <pubDate>Tue, 09 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/high-order-function-in-script-include-accessing-the-context-this/</guid>
      <description>how to access this context when using high order functions in a ServiceNow script include.</description>
      <content:encoded><![CDATA[<p>In the Service-Now script includes (or in Javascript in general), the context of the <code>this</code> in not reachable when using high order function.</p>
<p>This might be obvious for some of you, but it was not for me and I struggled some time to achieve what I wanted in a <em>clean</em> manner. Hence this post.</p>
<p>You are maybe wondering what are high order functions? Well this can be defined as follow :</p>
<blockquote>
<p>Functions that operate on other functions, either by taking them as arguments or by returning them, are called <em>higher-order functions</em>.</p>
<p>-- Marijn Haverbeke, <em>Eloquent JavaScript, 3rd edition</em></p>
</blockquote>
<p>Practically this is what is used when using for example call-back functions or whenever you are passing a function as an argument to another function.</p>
<p>When doing so, <code>this</code> refers to the context. In Service-Now script include, it is typically used to reference global variables, that are accessible by all the functions within the script include, and to call other functions inside of the script include.</p>
<h2 id="common-usage-of-this">common usage of <code>this</code></h2>
<p>For example, in the following code we are use <code>this</code> to access the variable <code>setInit</code> and to call the function <code>myOtherFunction</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">test</span> <span class="o">=</span> <span class="nx">Class</span><span class="p">.</span><span class="nx">create</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">test</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">initialize</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="o">=</span> <span class="s2">&#34;Set in init&#34;</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="nx">myFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in myfunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">myOtherFunction</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">myOtherFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callBack</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in myOtherFunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">type</span><span class="o">:</span> <span class="s1">&#39;test&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="this-context-is-lost-when-calling-a-function-given-as-a-parameter-to-another-function"><code>this</code> context is lost when calling a function given as a parameter to another function</h2>
<p>Now let&rsquo;s imagine with we need to pass a function as an argument to another function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">	 <span class="nx">initialize</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="o">=</span> <span class="s2">&#34;Set in init&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">doFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in doFunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">processFunction</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">postProcessFunction</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">processFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callBack</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in processFunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">postProcessFunction</span><span class="p">(</span><span class="s2">&#34;from processfunction&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">postProcessFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">text</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// now this. is not referencing to the global context of the script inclue
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in processFunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span> <span class="c1">// can not access the value defined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">this</span><span class="p">.</span><span class="nx">doSomethingElseFunction</span> <span class="p">(</span><span class="s2">&#34;fromProcessfunction&#34;</span><span class="p">);</span> <span class="c1">// can not call this function
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">doSomethingElseFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">text</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>In order to solve this, we need to indicate that we want that the function <code>postProcessFunction</code> provided as an argument to <code>processFunction</code> has its <code>this</code>keyword set to the correct value, which is the global context.</p>
<h2 id="adding-the-bind-method-to-bound-the-context-to-the-function">Adding the <code>bind</code> method to bound the context to the function</h2>
<p>To do so, we need to add <code>.bind</code> method when passing the function as a parameter to <code>processFunction</code>, with the current context which is <code>this</code> :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"> 	<span class="nx">initialize</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="o">=</span> <span class="s2">&#34;Set in init&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">doFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in doFunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// Here we add the .bind method, with this as an argument
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">this</span><span class="p">.</span><span class="nx">processFunction</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">postProcessFunction</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span> 
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">processFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">callBack</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in processFunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">postProcessFunction</span><span class="p">(</span><span class="s2">&#34;from processfunction&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">postProcessFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">text</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// now this. IS referencing to the global context of the script inclue
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;value of setInit in processFunction: &#34;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">setInit</span><span class="p">);</span> <span class="c1">// CAN access the value defined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">this</span><span class="p">.</span><span class="nx">doSomethingElseFunction</span> <span class="p">(</span><span class="s2">&#34;fromProcessfunction&#34;</span><span class="p">);</span> <span class="c1">// CAN call this function
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="nx">doSomethingElseFunction</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">gs</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="nx">text</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><h2 id="real-life-usage-example">Real life usage example</h2>
<p>You may wonder what are real world use cases, so let me describe you one situation where I used <em>this</em>.</p>
<p>I needed to call REST messages for various interfaces. The bulk of the REST messages call is common to all, just the message name and the actions to perform after a successful execution or after an error where different.</p>
<p>To do so, I used functions as in simplified example below.</p>
<p>The function called to trigger the interface is <code>getUserDetails</code>. It then call the <code>executeRestMessage</code> with the REST message name and the post processing function and the error processing function as parameter. Note there the <code>bind</code> used when passing the function as a parameter.</p>
<p>The in the real case, there is multiple functions similar as <code>getUserDetails</code> and the logic is a bit more complexe.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">	  <span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@name getUserDetails
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@description Trigger the integration for getUserDetails
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="nx">getUserDetails</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// call the execute MEssage for this interface and with the function. Note the &#34;bind&#34; used.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">this</span><span class="p">.</span><span class="nx">executeMessage</span><span class="p">(</span><span class="s2">&#34;users&#34;</span><span class="p">,</span> <span class="s2">&#34;getUserDetails&#34;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">getUserDetails_postProcess</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">),</span> <span class="k">this</span><span class="p">.</span><span class="nx">getUserDetails_errorProcess</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">		@name executeRestMessage
</span></span></span><span class="line"><span class="cl"><span class="cm">		@description Execute the given REST message.If provided add string to endpoint and add query paramters. Then execute the given post process function.
</span></span></span><span class="line"><span class="cl"><span class="cm">		@param {String} [messageName] - Name of the REST message
</span></span></span><span class="line"><span class="cl"><span class="cm">		@param {String} [methodName] - Name of the http method 
</span></span></span><span class="line"><span class="cl"><span class="cm">		@param {function} {postProcessFunction} - Function to execution afer sucessfull execution of the REST Message
</span></span></span><span class="line"><span class="cl"><span class="cm">		@param {function} [errorProcessFunction] - Function to execution afer error in execution of the REST Message
</span></span></span><span class="line"><span class="cl"><span class="cm">	*/</span>
</span></span><span class="line"><span class="cl">	<span class="nx">executeRestMessage</span> <span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">messageName</span><span class="p">,</span> <span class="nx">methodName</span><span class="p">,</span> <span class="nx">postProcessFunction</span><span class="p">,</span> <span class="nx">errorProcessFunction</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// get REST message
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sn_ws</span><span class="p">.</span><span class="nx">RESTMessageV2</span><span class="p">(</span><span class="nx">messageName</span><span class="p">,</span> <span class="nx">methodName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// execute message
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>         <span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">message</span><span class="p">.</span><span class="nx">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// get http status from the response
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kd">var</span> <span class="nx">httpStatus</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">getStatusCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">               
</span></span><span class="line"><span class="cl">        <span class="c1">// in case of success, call the postProcessFunction
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="nx">httpStatus</span> <span class="o">==</span> <span class="s1">&#39;200&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="nx">postProcessFunction</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// or in case of error, call errorProcessFunction
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">errorProcessFunction</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">getBody</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">     <span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@name getUserDetails_postProcess
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@description Post processing for getUserDetails
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@param {String} [responseBody] - Response body from REST execution
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">	<span class="nx">getUserDetails_postProcess</span> <span class="p">(</span><span class="nx">responseBody</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// do post processing, update record, etc. &#34;this&#34; is accessible if needed
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        
</span></span><span class="line"><span class="cl">    <span class="p">},</span> 
</span></span><span class="line"><span class="cl">    <span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@name getUserDetails_errorProcess
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@description Error processing for getUserDetails
</span></span></span><span class="line"><span class="cl"><span class="cm">      	@param {String} [responseBody] - Response body from REST execution
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="nx">getUserDetails_errorProcess</span><span class="p">(</span><span class="nx">responseBody</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// do error processing (create incident, log message, etc..). &#34;this&#34; is accessible if needed
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>    
</span></span></code></pre></div><p>I hope you find this information and this example usefull. Please fell free to leave any message or to open a discussion on this topic in the comments below.</p>
<h2 id="references">References</h2>
<ol>
<li>Marijn Haverbeke, Eloquent JavaScript, 3rd edition,<a href="https://eloquentjavascript.net/Eloquent_JavaScript.pdf">https://eloquentjavascript.net/Eloquent_JavaScript.pdf</a>, 2018</li>
<li>Mozilla, MDM web docs, Function.prototype.bind(), <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind</a>, 2020 04 29</li>
<li>Alex Devro, Blog, How &ldquo;this&rdquo; in javaScript work,<a href="https://blog.alexdevero.com/this-in-javascript-works/"> https://blog.alexdevero.com/this-in-javascript-works/</a>, 2020 04 20</li>
</ol>]]></content:encoded>
    </item>
    
    <item>
      <title>Enable PlugIn</title>
      <link>https://www.snow-adventures.com/posts/enable-plugin/</link>
      <pubDate>Mon, 08 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://www.snow-adventures.com/posts/enable-plugin/</guid>
      <description>Using script to enable a PlugIn</description>
      <content:encoded><![CDATA[<p>This is a quick note about how to enable a PlugIn by script</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">pluginArr</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;com.sn_glidequery&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">pluginMgr</span><span class="o">=</span> <span class="k">new</span> <span class="nx">GlideMultiPluginManagerWorker</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">setPluginIds</span><span class="p">(</span><span class="nx">pluginArr</span> <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">setProgressName</span><span class="p">(</span><span class="s2">&#34;Plugin Installer&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">setBackground</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">pluginMgr</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span>
</span></span></code></pre></div><h2 id="reference">Reference</h2>
<ol>
<li>Ashby, <a href="https://community.servicenow.com/community?id=community_question&amp;sys_id=e6db5e4bdb47ab002e8c2183ca9619a2#answer_a8ddb159db407388feb1a851ca9619fa">NOW community - Activate plugin via script / automatically</a>, accessed 2020 06 10</li>
</ol>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
