<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>post Why Doesn't This Work?  Or, A Puzzle Explained... in In other news</title>
    <link>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/ba-p/2282445</link>
    <description>&lt;P&gt;&lt;SPAN class="asset-asset_lightbox-Small asset-align-right"&gt;&lt;A href="https://www.servicenow.com/files/SlightlyLoony/oldmanwtf.jpg" rel="lightbox"&gt;&lt;IMG rel="lightbox" src="http://community.service-now.com/files/imagecache/Small/SlightlyLoony/oldmanwtf.jpg" alt="" title="" class="imagecache imagecache-Small" /&gt;&lt;/A&gt;&lt;/SPAN&gt;I'm told that just a few weeks ago, our correspondent at right looked like the young man he actually is. Then he tried to write what he thought was a simple little script on his company's ServiceNow instance. After a few days that involved facepalms, banging his head against the wall, banging other people's heads against the wall, screaming, and some possibly licit intoxicants … he looked like this.&lt;BR /&gt;&lt;BR /&gt;He should have contacted me earlier. He was doing &lt;I&gt;almost&lt;/I&gt; everything correctly. All he was missing was one key piece of understanding, and the answer would have been obvious.&lt;BR /&gt;&lt;BR /&gt;He needed to understand composite tables.&lt;BR /&gt;&lt;!--break--&gt;&lt;BR /&gt;First, let's look at his code that didn't work. He was trying to write a function which, given the IP address of a computer, would return its name. His function worked fine for workstations and laptops, but not for servers. Here's what he had:&lt;BR /&gt;&lt;PRE style="margin-left:20px;line-height:1;color:FireBrick;"&gt;&lt;BR /&gt;gs.log(findName('10.0.10.69'));&lt;BR /&gt;&lt;BR /&gt;function findName(ip) {&lt;BR /&gt;    var gr = new GlideRecord('cmdb_ci_ip_address');&lt;BR /&gt;    gr.addQuery('ip_address', ip);&lt;BR /&gt;    gr.query();&lt;BR /&gt;    if (!gr.next())&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var nic_id = '' + gr.nic;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_network_adapter');&lt;BR /&gt;    if (!gr.get(nic_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var computer_id = '' + gr.cmdb_ci;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_computer');&lt;BR /&gt;    if (!gr.get(computer_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var kind = '' + gr.sys_class_name;&lt;BR /&gt;    if (kind == 'cmdb_ci_computer')&lt;BR /&gt;        return '' + gr.name;&lt;BR /&gt;&lt;BR /&gt;    return '' + gr.host_name;&lt;BR /&gt;}&lt;/PRE&gt;&lt;BR /&gt;Most of this is quite straightforward code that navigates through the CMDB database. First it finds the IP address table record with the desired IP address, then it uses that record's reference (&lt;I&gt;nic&lt;/I&gt;) to locate the NIC (network adapter) record that is provisioned for that IP address. Once it has the NIC, it uses that record's CI reference (&lt;I&gt;cmdb_ci&lt;/I&gt;) to locate the computer that the NIC is installed in. If any of this logic fails, it simply returns a null. So far, this is all just fine.&lt;BR /&gt;&lt;BR /&gt;Right near the end is where our prematurely old friend goes horribly wrong. His code looks at the class name (&lt;I&gt;sys_class_name&lt;/I&gt;) of the computer record to see if it's a plain old computer (which would mean it was a workstation or laptop) or something else (which would mean it was some kind of server). If it's a computer, it returns the contents of the name field — this is the part the works just fine. But if it's a server, it tries to return the host name (a field that only servers have). This fails miserably, returning an 'undefined'. Our aged friend can go look at the record for the server with that IP address, and the host name is staring him right in the face. It's &lt;I&gt;there&lt;/I&gt;, dang it! What's up with the undefined?&lt;BR /&gt;&lt;BR /&gt;The problem is that his code queried &lt;I&gt;cmdb_ci_computer&lt;/I&gt;, not the actual server table. So what? Well, that's where you really need to understand composite tables...&lt;BR /&gt;&lt;BR /&gt;When you query the &lt;I&gt;cmdb_ci_computer&lt;/I&gt; table, under the covers the ServiceNow instance is actually joining three tables together to produce the results you find in your GlideRecord instance:&lt;BR /&gt;&lt;/P&gt;&lt;DIV style="margin-left:20px;margin-bottom:10px;line-height:1;color:FireBrick;"&gt;cmdb_ci â‰¡ cmdb_ci_hardware â‰¡ cmdb_ci_computer&lt;/DIV&gt;&lt;BR /&gt;All of the columns in all three of those tables are available to your GlideRecord instance. Our wizened friend's problem is that the &lt;I&gt;host_name&lt;/I&gt; column is not in any of those tables — hence the undefined. Facepalm time.&lt;BR /&gt;&lt;BR /&gt;The fix is very straightforward — just "re-get" the record in question using a glide record for the actual class:&lt;BR /&gt;&lt;PRE style="margin-left:20px;line-height:1;color:FireBrick;"&gt;&lt;BR /&gt;gs.log(findName('10.0.10.69'));&lt;BR /&gt;&lt;BR /&gt;function findName(ip) {&lt;BR /&gt;    var gr = new GlideRecord('cmdb_ci_ip_address');&lt;BR /&gt;    gr.addQuery('ip_address', ip);&lt;BR /&gt;    gr.query();&lt;BR /&gt;    if (!gr.next())&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var nic_id = '' + gr.nic;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_network_adapter');&lt;BR /&gt;    if (!gr.get(nic_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var computer_id = '' + gr.cmdb_ci;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_computer');&lt;BR /&gt;    if (!gr.get(computer_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var kind = '' + gr.sys_class_name;&lt;BR /&gt;    if (kind == 'cmdb_ci_computer')&lt;BR /&gt;        return '' + gr.name;&lt;BR /&gt;&lt;BR /&gt;    gr = new GlideRecord(kind);&lt;BR /&gt;    if (!gr.get(computer_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    return '' + gr.host_name;&lt;BR /&gt;}&lt;/PRE&gt;&lt;BR /&gt;&lt;I&gt;Voila!&lt;/I&gt; This produces exactly the results that our antique friend wanted. Why? Well, in the case of our example, the computer in question was a Linux server. By using a query against &lt;I&gt;cmdb_ci_linux_server&lt;/I&gt;, our GlideRecord joined five tables together to give us the results:&lt;BR /&gt;&lt;DIV style="margin-left:20px;margin-bottom:10px;line-height:1;color:FireBrick;"&gt;cmdb_ci â‰¡ cmdb_ci_hardware â‰¡ cmdb_ci_computer â‰¡ cmdb_ci_server â‰¡ cmdb_ci_linux_server&lt;/DIV&gt;&lt;BR /&gt;The first three tables are the same as before, but the last two hold the key to the mystery: the &lt;I&gt;host_name&lt;/I&gt; column is part of the &lt;I&gt;cmdb_ci_server&lt;/I&gt; table. By querying (in this case) the Linux server table, the &lt;I&gt;cmdb_ci_server&lt;/I&gt; table is automatically included in the query.&lt;BR /&gt;&lt;BR /&gt;How can you tell what attributes are in what table? Very easily! Just navigate to a list or form with examples of the table you're wondering about, right click on the bar, and select &lt;I&gt;Personalize â†’ Dictionary&lt;/I&gt;. You'll get a list of all the columns available to that table, including all those columns that are joined together when you query that table through GlideRecord. The &lt;I&gt;Table&lt;/I&gt; column tells you which table any particular column is in.&lt;BR /&gt;&lt;BR /&gt;Now we just need to find the fountain of youth for our old goat...&lt;P&gt;&lt;/P&gt;</description>
    <pubDate>Fri, 21 Oct 2011 13:50:50 GMT</pubDate>
    <dc:creator>SlightlyLoony</dc:creator>
    <dc:date>2011-10-21T13:50:50Z</dc:date>
    <item>
      <title>Why Doesn't This Work?  Or, A Puzzle Explained...</title>
      <link>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/ba-p/2282445</link>
      <description>&lt;P&gt;&lt;SPAN class="asset-asset_lightbox-Small asset-align-right"&gt;&lt;A href="https://www.servicenow.com/files/SlightlyLoony/oldmanwtf.jpg" rel="lightbox"&gt;&lt;IMG rel="lightbox" src="http://community.service-now.com/files/imagecache/Small/SlightlyLoony/oldmanwtf.jpg" alt="" title="" class="imagecache imagecache-Small" /&gt;&lt;/A&gt;&lt;/SPAN&gt;I'm told that just a few weeks ago, our correspondent at right looked like the young man he actually is. Then he tried to write what he thought was a simple little script on his company's ServiceNow instance. After a few days that involved facepalms, banging his head against the wall, banging other people's heads against the wall, screaming, and some possibly licit intoxicants … he looked like this.&lt;BR /&gt;&lt;BR /&gt;He should have contacted me earlier. He was doing &lt;I&gt;almost&lt;/I&gt; everything correctly. All he was missing was one key piece of understanding, and the answer would have been obvious.&lt;BR /&gt;&lt;BR /&gt;He needed to understand composite tables.&lt;BR /&gt;&lt;!--break--&gt;&lt;BR /&gt;First, let's look at his code that didn't work. He was trying to write a function which, given the IP address of a computer, would return its name. His function worked fine for workstations and laptops, but not for servers. Here's what he had:&lt;BR /&gt;&lt;PRE style="margin-left:20px;line-height:1;color:FireBrick;"&gt;&lt;BR /&gt;gs.log(findName('10.0.10.69'));&lt;BR /&gt;&lt;BR /&gt;function findName(ip) {&lt;BR /&gt;    var gr = new GlideRecord('cmdb_ci_ip_address');&lt;BR /&gt;    gr.addQuery('ip_address', ip);&lt;BR /&gt;    gr.query();&lt;BR /&gt;    if (!gr.next())&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var nic_id = '' + gr.nic;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_network_adapter');&lt;BR /&gt;    if (!gr.get(nic_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var computer_id = '' + gr.cmdb_ci;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_computer');&lt;BR /&gt;    if (!gr.get(computer_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var kind = '' + gr.sys_class_name;&lt;BR /&gt;    if (kind == 'cmdb_ci_computer')&lt;BR /&gt;        return '' + gr.name;&lt;BR /&gt;&lt;BR /&gt;    return '' + gr.host_name;&lt;BR /&gt;}&lt;/PRE&gt;&lt;BR /&gt;Most of this is quite straightforward code that navigates through the CMDB database. First it finds the IP address table record with the desired IP address, then it uses that record's reference (&lt;I&gt;nic&lt;/I&gt;) to locate the NIC (network adapter) record that is provisioned for that IP address. Once it has the NIC, it uses that record's CI reference (&lt;I&gt;cmdb_ci&lt;/I&gt;) to locate the computer that the NIC is installed in. If any of this logic fails, it simply returns a null. So far, this is all just fine.&lt;BR /&gt;&lt;BR /&gt;Right near the end is where our prematurely old friend goes horribly wrong. His code looks at the class name (&lt;I&gt;sys_class_name&lt;/I&gt;) of the computer record to see if it's a plain old computer (which would mean it was a workstation or laptop) or something else (which would mean it was some kind of server). If it's a computer, it returns the contents of the name field — this is the part the works just fine. But if it's a server, it tries to return the host name (a field that only servers have). This fails miserably, returning an 'undefined'. Our aged friend can go look at the record for the server with that IP address, and the host name is staring him right in the face. It's &lt;I&gt;there&lt;/I&gt;, dang it! What's up with the undefined?&lt;BR /&gt;&lt;BR /&gt;The problem is that his code queried &lt;I&gt;cmdb_ci_computer&lt;/I&gt;, not the actual server table. So what? Well, that's where you really need to understand composite tables...&lt;BR /&gt;&lt;BR /&gt;When you query the &lt;I&gt;cmdb_ci_computer&lt;/I&gt; table, under the covers the ServiceNow instance is actually joining three tables together to produce the results you find in your GlideRecord instance:&lt;BR /&gt;&lt;/P&gt;&lt;DIV style="margin-left:20px;margin-bottom:10px;line-height:1;color:FireBrick;"&gt;cmdb_ci â‰¡ cmdb_ci_hardware â‰¡ cmdb_ci_computer&lt;/DIV&gt;&lt;BR /&gt;All of the columns in all three of those tables are available to your GlideRecord instance. Our wizened friend's problem is that the &lt;I&gt;host_name&lt;/I&gt; column is not in any of those tables — hence the undefined. Facepalm time.&lt;BR /&gt;&lt;BR /&gt;The fix is very straightforward — just "re-get" the record in question using a glide record for the actual class:&lt;BR /&gt;&lt;PRE style="margin-left:20px;line-height:1;color:FireBrick;"&gt;&lt;BR /&gt;gs.log(findName('10.0.10.69'));&lt;BR /&gt;&lt;BR /&gt;function findName(ip) {&lt;BR /&gt;    var gr = new GlideRecord('cmdb_ci_ip_address');&lt;BR /&gt;    gr.addQuery('ip_address', ip);&lt;BR /&gt;    gr.query();&lt;BR /&gt;    if (!gr.next())&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var nic_id = '' + gr.nic;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_network_adapter');&lt;BR /&gt;    if (!gr.get(nic_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var computer_id = '' + gr.cmdb_ci;&lt;BR /&gt;    gr = new GlideRecord('cmdb_ci_computer');&lt;BR /&gt;    if (!gr.get(computer_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    var kind = '' + gr.sys_class_name;&lt;BR /&gt;    if (kind == 'cmdb_ci_computer')&lt;BR /&gt;        return '' + gr.name;&lt;BR /&gt;&lt;BR /&gt;    gr = new GlideRecord(kind);&lt;BR /&gt;    if (!gr.get(computer_id))&lt;BR /&gt;        return null;&lt;BR /&gt;&lt;BR /&gt;    return '' + gr.host_name;&lt;BR /&gt;}&lt;/PRE&gt;&lt;BR /&gt;&lt;I&gt;Voila!&lt;/I&gt; This produces exactly the results that our antique friend wanted. Why? Well, in the case of our example, the computer in question was a Linux server. By using a query against &lt;I&gt;cmdb_ci_linux_server&lt;/I&gt;, our GlideRecord joined five tables together to give us the results:&lt;BR /&gt;&lt;DIV style="margin-left:20px;margin-bottom:10px;line-height:1;color:FireBrick;"&gt;cmdb_ci â‰¡ cmdb_ci_hardware â‰¡ cmdb_ci_computer â‰¡ cmdb_ci_server â‰¡ cmdb_ci_linux_server&lt;/DIV&gt;&lt;BR /&gt;The first three tables are the same as before, but the last two hold the key to the mystery: the &lt;I&gt;host_name&lt;/I&gt; column is part of the &lt;I&gt;cmdb_ci_server&lt;/I&gt; table. By querying (in this case) the Linux server table, the &lt;I&gt;cmdb_ci_server&lt;/I&gt; table is automatically included in the query.&lt;BR /&gt;&lt;BR /&gt;How can you tell what attributes are in what table? Very easily! Just navigate to a list or form with examples of the table you're wondering about, right click on the bar, and select &lt;I&gt;Personalize â†’ Dictionary&lt;/I&gt;. You'll get a list of all the columns available to that table, including all those columns that are joined together when you query that table through GlideRecord. The &lt;I&gt;Table&lt;/I&gt; column tells you which table any particular column is in.&lt;BR /&gt;&lt;BR /&gt;Now we just need to find the fountain of youth for our old goat...&lt;P&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 21 Oct 2011 13:50:50 GMT</pubDate>
      <guid>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/ba-p/2282445</guid>
      <dc:creator>SlightlyLoony</dc:creator>
      <dc:date>2011-10-21T13:50:50Z</dc:date>
    </item>
    <item>
      <title>Re: Why Doesn't This Work?  Or, A Puzzle Explained...</title>
      <link>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/bc-p/2282446#M5366</link>
      <description>&lt;P&gt;How about getting from a computer name back down to the (somehow) associated record in cmdb_ci named "eth0"?&lt;BR /&gt;&lt;BR /&gt;Let's say I'm looking for the eth0 record for a computer named X. What table fields need to be walked to connect the dots?&lt;BR /&gt;&lt;BR /&gt;Have looked at the Personalize -&amp;gt; Dictionary page of the Network Adapters tab of a CI in the linux servers class, but somehow still missing the connection.&lt;BR /&gt;&lt;BR /&gt;Thank you.&lt;/P&gt;&lt;BR /&gt;</description>
      <pubDate>Sat, 29 Oct 2011 20:24:23 GMT</pubDate>
      <guid>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/bc-p/2282446#M5366</guid>
      <dc:creator />
      <dc:date>2011-10-29T20:24:23Z</dc:date>
    </item>
    <item>
      <title>Re: Why Doesn't This Work?  Or, A Puzzle Explained...</title>
      <link>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/bc-p/2282447#M5367</link>
      <description>&lt;P&gt;If you look at the dictionary, as you described, you'll see that there is a column named "cmdb_ci" that is a reference to a record in the cmdb_ci table. That's the key: each network adapter that belongs to a particular computer has a reference to that computer in that field. Here's some code to demonstrate. The assumption here is that we give our function the computer name and the network adapter name, and it will return either the GlideRecord with the network adapter in it, or null if it couldn't find either the computer or the network adapter. Here you go:&lt;BR /&gt;&lt;BR /&gt;function getNIC(computer, nic) {&lt;BR /&gt; var gr = new GlideRecord('cmdb_ci_computer');&lt;BR /&gt; gr.addQuery('name', computer);&lt;BR /&gt; gr.query();&lt;BR /&gt; if (!gr.next())&lt;BR /&gt; return null;&lt;BR /&gt;&lt;BR /&gt; var nic_gr = new GlideRecord('cmdb_ci_network_adapter');&lt;BR /&gt; nic_gr.addQuery('name', nic);&lt;BR /&gt; nic_gr.addQuery('cmdb_ci', gr.sys_id); // &amp;lt;-- the important bit!&lt;BR /&gt; nic_gr.query();&lt;BR /&gt; return nic_gr.next() ? nic_gr : null;&lt;BR /&gt;}&lt;/P&gt;&lt;BR /&gt;</description>
      <pubDate>Sat, 29 Oct 2011 21:01:30 GMT</pubDate>
      <guid>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/bc-p/2282447#M5367</guid>
      <dc:creator>SlightlyLoony</dc:creator>
      <dc:date>2011-10-29T21:01:30Z</dc:date>
    </item>
    <item>
      <title>Re: Why Doesn't This Work?  Or, A Puzzle Explained...</title>
      <link>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/bc-p/2282448#M5368</link>
      <description>&lt;P&gt;Instead of 're-get' the CI, you can just use the "ref_" especial prefix to get fields from any sub-table:&lt;BR /&gt;&lt;BR /&gt;&lt;PRE __default_attr="plain" __jive_macro_name="code" class="jive_text_macro jive_macro_code"&gt;&lt;BR /&gt;...&lt;BR /&gt;if (kind == 'cmdb_ci_computer')&lt;BR /&gt;        return '' + gr.name;&lt;BR /&gt;&lt;BR /&gt;return '' + gr.ref_cmdb_ci_server.host_name;&lt;BR /&gt;&lt;/PRE&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;span class="lia-unicode-emoji" title=":winking_face:"&gt;😉&lt;/span&gt;&lt;BR /&gt;&lt;/P&gt;&lt;BR /&gt;</description>
      <pubDate>Tue, 22 Oct 2013 07:54:45 GMT</pubDate>
      <guid>https://www.servicenow.com/community/in-other-news/why-doesn-t-this-work-or-a-puzzle-explained/bc-p/2282448#M5368</guid>
      <dc:creator>jesjuar</dc:creator>
      <dc:date>2013-10-22T07:54:45Z</dc:date>
    </item>
  </channel>
</rss>

