6
\$\begingroup\$

I'm trying to display data from Keen.io we're collecting from an iOS app where we report what devices of ours the app is used to communicate with. In particular I'm trying to find where there are more than one of our device.

An entry from the Keen collection looks like:

{
  "iOS_OpenUDID": "hexadecimal",
  "iOS_CountryCode": "two-letter country code",
  "Device": {
    "SerialNumber": "numbers",
    "Barcode": "numbers",
    "IP": "IP address",
    "Model": "string",
  },
  "iOS_Timezone": "name of timezone",
}

Most of this is adapted from various different examples and tutorials, and as far as I can tell, it works. Examples I remember using are:

I have no idea though if it's 'good' code or 'awful', so please give constructive criticism:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Cache-Control" content="no-cache, mustrevalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type='text/javascript' src='https://www.google.com/jsapi'></script>

<title>Multiple Devices</title>

<script type="text/javascript">
var Keen=Keen||{configure:function(e){this._cf=e},addEvent:function(e,t,n,i){this._eq=this._eq||[],this._eq.push([e,t,n,i])},setGlobalProperties:function(e){this._gp=e},onChartsReady:function(e){this._ocrq=this._ocrq||[],this._ocrq.push(e)}};(function(){var e=document.createElement("script");e.type="text/javascript",e.async=!0,e.src=("https:"==document.location.protocol?"https://":"http://")+"dc8na2hxrj29i.cloudfront.net/code/keen-2.1.0-min.js";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)})();

Keen.configure({
    projectId: "REMOVED",
    readKey: "REMOVED"
});

// From http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
function eliminateDuplicates(arr) {
    var i,
        len=arr.length,
        out=[],
        obj={};

    for (i=0;i<len;i++) {
        obj[arr[i]]=0;
    }
    for (i in obj) {
        out.push(i);
    }
    return out;
}

google.load('visualization', '1', {packages:['table']});
google.setOnLoadCallback(drawTable);
function drawTable() {
    var datatable = new google.visualization.DataTable();
    datatable.addColumn('string', 'iOS OpenUDID');
    datatable.addColumn('string', 'Models (Barcode, Serial Number, IP address)');
    datatable.addColumn('string', 'App Brand');
    datatable.addColumn('string', 'iOS Timezone');

    var table = new google.visualization.Table(document.getElementById('table_div'));

    var metric = new Keen.Metric("Devices", {
        analysisType: "count_unique",
        targetProperty: "Device.IP",
        groupBy: "iOS_OpenUDID",
        filters: [
            {"property_name":"iOS_OpenUDID","operator":"exists","property_value":true},
        ]
    });
    metric.getResponse(function(response){
        // console.log(response);

        for (var id = 0; id < response.result.length; id++) {
            if (response.result[id].result > 1) {
//              console.log(response.result[id]);
                var query = "https://api.keen.io/3.0/projects/REMOVED/queries/extraction?api_key=DEVICES&event_collection=Devices&timezone=43200&target_property=Device.Model&group_by=Device.Model&filters=%5B%7B%22property_name%22%3A%22iOS_OpenUDID%22%2C%22operator%22%3A%22eq%22%2C%22property_value%22%3A%22" + response.result[id].iOS_OpenUDID + "%22%7D%5D";
                $.getJSON(query, function(data) {
//                  console.log(data);

                    var arr = [];
                    for (var i = 0; i < data.result.length; i++) {
                        if (data.result[i] !== undefined && data.result[i] !== null) {
                            var string = data.result[i].Device["Model"];
                            var string2 = "";
                            if (data.result[i].Device["Barcode"] !== undefined && data.result[i].Device["Barcode"] !== null) {
                                string2 += data.result[i].Device["Barcode"];
                            }
                            if (data.result[i].Device["SerialNumber"] !== undefined && data.result[i].Device["SerialNumber"] !== null) {
                                if (string2.length > 0) {
                                    string2 += ", ";
                                }
                                string2 += data.result[i].Device["SerialNumber"];
                            }
                            if (data.result[i].Device["IP"] !== undefined && data.result[i].Device["IP"] !== null) {
                                if (string2.length > 0) {
                                    string2 += ", ";
                                }
                                string2 += data.result[i].Device["IP"];
                            }
                            if (string2.length > 0) {
                                string += " (" + string2 + ")";
                            }

                            arr.push(string);
                        }
                    };

                    arr = eliminateDuplicates(arr);
                    var models = "";
                    for (var i = 0; i < arr.length; i++) {
                        if (models.length > 0) {
                            models += ", ";
                        }
                        models += arr[i];
                    }

                    datatable.addRow(
                        [data.result[0]["iOS_OpenUDID"], models, data.result[0]["Brand"], data.result[0]["iOS_Timezone"]]
                    );

                    table.draw(datatable, {showRowNumber: true});
                })
                .fail(function(jqXHR, textStatus, errorThrown) { alert('getJSON request failed! ' + textStatus); });
            }
        }
    });

    table.draw(datatable, {showRowNumber: true});
}
</script>

<style type="text/css">
  body { padding-top: 70px; }
</style>


</head>

<body>

    <div id='table_div'></div>

</body>
</html>
\$\endgroup\$
0

2 Answers 2

2
\$\begingroup\$

Nice work, @parsley72! This is a really clever mashup, no reason to suspect it's "not good" or even "awful" :)

[Keen IO employee here, fwiw]

One characteristic worth considering is reusability, but since this seems to be a fairly specialized bit of code I wouldn't spend too much time there. If you do find yourself repeating operations, there might be the beginnings of a reusable utility hiding in there somewhere. And if that's the case, please let me know.. it may be handy enough for us to roll into the library.

\$\endgroup\$
2
\$\begingroup\$

Entire eliminateDuplicates() function can be now replaced simply with [...new Set(arr)].


Callback of $.getJSON can be simplified. Instead of sea of ifs to filter out undefineds and nulls and to join elements with a comma, it can be done this way:

const models = new Set();

for (const result of data.result) {
  if (result === undefined || result === null) { continue; }

  const arr = [result.Device.Barcode, result.Device.SerialNumber, result.Device.IP]
              .filter(data => data !== undefined && data !== null).join(', ');

  models.add(result.Device.Model + (arr.length > 0 ? ` (${arr})` : ''));
}

First all data get into an array, then undefineds and nulls get filtered out, and all entries are joined with ,. If there is anything in that array it get's appended to what will be added to models. Notice also, that since models is a Set and not an array, it does not have to be checked for duplicates.


In your query, response.result[id].iOS_OpenUDID is not encoded, while another part of it is (value of filters param), worsening readability. Another approach:

const filters = encodeURIComponent(`[{"property_name":"iOS_OpenUDID","operator":"eq","property_value":"${that.iOS_OpenUDID}"}]`);
const query = '………' + filters;

Rewrite

var Keen=Keen||{configure:function(e){this._cf=e},addEvent:function(e,t,n,i){this._eq=this._eq||[],this._eq.push([e,t,n,i])},setGlobalProperties:function(e){this._gp=e},onChartsReady:function(e){this._ocrq=this._ocrq||[],this._ocrq.push(e)}};(function(){var e=document.createElement('script');e.type='text/javascript',e.async=!0,e.src=('https:'==document.location.protocol?'https://':'http://')+'dc8na2hxrj29i.cloudfront.net/code/keen-2.1.0-min.js';var t=document.getElementsByTagName('script')[0];t.parentNode.insertBefore(e,t)})();

Keen.configure({
  projectId: 'REMOVED',
  readKey:   'REMOVED'
});

google.load('visualization', '1', {packages:['table']});
google.setOnLoadCallback(drawTable);

const datatable = new google.visualization.DataTable();

datatable.addColumn('string', 'iOS OpenUDID');
datatable.addColumn('string', 'Models (Barcode, Serial Number, IP address)');
datatable.addColumn('string', 'App Brand');
datatable.addColumn('string', 'iOS Timezone');

const table = new google.visualization.Table(document.getElementById('table_div'));

const onFetch = data => {
  // console.log(data);

  const models = new Set();

  for (const result of data.result) {
    if (result === undefined || result === null) { continue; }

    const arr = [result.Device.Barcode, result.Device.SerialNumber, result.Device.IP]
                 .filter(data => data !== undefined && data !== null).join(', ');

    models.add(result.Device.Model + (arr.length > 0 ? ` (${arr})` : ''));
  }

  datatable.addRow([
    data.result[0].iOS_OpenUDID,
    [...models].join(', '),
    data.result[0].Brand,
    data.result[0].iOS_Timezone
  ]);

  table.draw(datatable, {showRowNumber: true});
};

function drawTable() {
  const metric = new Keen.Metric('Devices', {
    analysisType:   'count_unique',
    targetProperty: 'Device.IP',
    groupBy:        'iOS_OpenUDID',
    filters:        [{'property_name': 'iOS_OpenUDID', 'operator': 'exists', 'property_value': true}]
  });

  metric.getResponse(function(response) {
    // console.log(response);
    for (const that of response.result) {
      if (that.result <= 1) { continue; }
      // console.log(that);
      const filters = encodeURIComponent(`[{"property_name":"iOS_OpenUDID","operator":"eq","property_value":"${that.iOS_OpenUDID}"}]`);
      const query = 'https://api.keen.io/3.0/projects/REMOVED/queries/extraction?api_key=DEVICES&event_collection=Devices&timezone=43200&target_property=Device.Model&group_by=Device.Model&filters=' + filters;

      fetch(query).then(response => response.json()).then(onFetch).catch(reason =>
        alert(`fetch, JSONing or onFetch function failed. Reason: ${reason}`)
      );
    }
  });

  table.draw(datatable, {showRowNumber: true});
}
\$\endgroup\$
2
  • \$\begingroup\$ Ahoy! Do you ever intend to un-delete this answer? \$\endgroup\$ Oct 28, 2020 at 18:57
  • \$\begingroup\$ @SᴀᴍOnᴇᴌᴀ: done \$\endgroup\$
    – Przemek
    Feb 17, 2021 at 21:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.