将Keenio数据提取到Google电子表格中

时间:2018-06-24 14:57:26

标签: json google-apps-script google-sheets sendgrid keen-io

我当前正在通过 Sheet DATA 的Google Spreadsheet单元格中的ImportJSON函数,使用 ImportJSON 导入带有数据Keenio提取查询API URL的Sendgrid电子邮件。

=ImportJSON("https://api.keen.io/3.0/projects/"& PROJECT_KEY & "/queries/extraction?api_key=" & API_KEY & "&event_collection=" & EVT_COL & "&timezone=" & TIMEZONE & "&latest=" &  LATEST & "&property_names..........", PTDATA!$AB$1)

Sheet PTDATA 中,在最后一列单元格中,我为ImportJSON设置了一个随机数以重新计算。该函数在电子表格打开事件上运行。我还添加了一个自定义菜单来调用 ReCalcCell 自定义函数。

function onOpen() {
  var ui = SpreadsheetApp.getUi();

  // Or DocumentApp or FormApp.
  ui.createMenu('IMPORT DATA')
  .addItem('KEENIO DATA', 'ReCalcCell')
  .addToUi();
}


function ReCalcCell(){
  var min = Math.ceil(0);
  var max = Math.floor(9999);
  var randomNum = Math.floor(Math.random() * (max - min + 1)) + min 
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sh = ss.getSheetByName("PTDATA");
  sh.getRange("$AB$1").setValue(randomNum);
}

PTDATA工作表具有特定的列标题名称,我要从其中提取数据从 DATA工作表。在这些列的右侧,我还有其他计算列在这些特定列上工作。

由于数据表中的列始终以随机/随机排列的顺序出现,因此我不得不编写一个小的自定义函数 GCL ,该函数接受标头名称并返回其标题数据表中的数据范围地址作为字符串。

function GCL(header,dummy) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("DATA");
  var headings = sheet.getRange(1, 1, 1, sheet.getLastColumn()); // get the range representing the whole sheet
  var width = headings.getWidth();
  var lrow = sheet.getLastRow();

    // search every cell in row 1 from A1 till the last column
    for (var i = 1; i <= width; i++) {
        var data = headings.getCell(1,i).getValue();
        if (data == header) {
          return ((sheet.getSheetName() + "!" + columnToLetter(i)+"2:" + columnToLetter(i) + lrow).toString()); // return the column range if we find it
           break; // exit when found
        }
    }
    return(-1); // return -1 if it doesn't exist
}

function columnToLetter(column)
{
  var temp, letter = '';
  while (column > 0)
  {
    temp = (column - 1) % 26;
    letter = String.fromCharCode(temp + 65) + letter;
    column = (column - temp - 1) / 26;
  }
  return letter;
}

然后,我在每个特定列中使用自定义函数 GCL 来获取其数据范围。填充数据后, PDATA工作表将用于创建用于报告目的的不同数据透视表。

  

= ARRAYFORMULA(INDIRECT(GCL(A1,$ AB $ 1)))

我面临的问题是,尽管ImportJSON数据填充了数据表

数据表: enter image description here

  • 这些列每次都会被打乱,因此我的计算列无法随着引用的消失而进行计算。这使枢轴无用!为了解决这个问题,我必须创建 PDATA工作表,以使用自定义功能GCL 提取特定列。
  • 自定义功能GCL 并不总是刷新,并且大多数时间显示 #Ref错误

PDATA工作表: enter image description here

顺便说一句,我来自Keenio的 JSON输出如下:

{
"result":
[
{
"sg_event_id": "92-OndRfTs6fZjNdHWzLBw",
"timestamp": 1529618395,
"url": "https://noname.com?utm_campaign=website&utm_source=sendgrid.com&utm_medium=email",
"ip": "192.168.1.1",
"event": "click",
"keen": {
"timestamp": "2018-06-21T21:59:55.000Z",
"created_at": "2018-06-21T22:00:28.532Z",
"id": "555c1f7c5asdf7000167d87b"
},
"url_offset": {
"index": 38,
"type": "text"
},
"sg_message_id": "F5mwV1rESdyKFA_2bn1IEQ.filter0042p3las1-15933-5B2A68E8-36.0",
"useragent": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)",
"email": "no.name@noname.com"
}, {
"sg_event_id": "bjMlfsSfRyuXEVy8LndsYA",
"timestamp": 1529618349,
"url": "https://noname.com?utm_campaign=website&utm_source=sendgrid.com&utm_medium=email",
"ip": "192.168.1.1",
"event": "click",
"keen": {
"timestamp": "2018-06-21T21:59:09.000Z",
"created_at": "2018-06-21T21:59:39.491Z",
"id": "555c1f7c5asdf7000167d87b"
},
"url_offset": {
"index": 36,
"type": "text"
},
"sg_message_id": "F5mwV1rESdyKFA_2bn1IEQ.filter0042p3las1-15933-5B2A68E8-36.0",
"useragent": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)",
"email": "no.name@noname.com"
}, {
"sg_event_id": "fru_s2s1RtueuqBMNoIoTg",
"timestamp": 1529618255,
"url": "https://noname.com?utm_campaign=website&utm_source=sendgrid.com&utm_medium=email",
"ip": "192.168.1.1",
"event": "click",
"keen": {
"timestamp": "2018-06-21T21:57:35.000Z",
"created_at": "2018-06-21T21:58:20.374Z",
"id": "555c1f7c5asdf7000167d87b"
},
"url_offset": {
"index": 29,
"type": "text"
},
"sg_message_id": "F5mwV1rESdyKFA_2bn1IEQ.filter0042p3las1-15933-5B2A68E8-36.0",
"useragent": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)",
"email": "no.name@noname.com"
}
]
}

我的问题是:

  • 是否有一种无需使用ImportJSON即可解析JSON结果的方法,必须将它作为自定义函数输入到还依赖于重新计算的单元格中? ImportJSON有时可能无法正常工作。
  • 如何重构或优化此代码,使其始终可以将数据返回到PDATA工作表列?
  • 是否有更好的方式来实现我想要的功能,而无需借助自定义功能,例如PDATA工作表中的GCL或DATA工作表中的ImportJSON?

2 个答案:

答案 0 :(得分:1)

这个示例脚本怎么样?该脚本解析使用UrlFetchApp从API检索的值,并将它们放在工作表“ DATA”中。您可以在电子表格菜单上运行它。在运行此程序之前,请放置端点。

示例脚本:

function onOpen() {
  var ui = SpreadsheetApp.getUi();

  // Or DocumentApp or FormApp.
  ui.createMenu('IMPORT DATA')
  .addItem('KEENIO DATA', 'ReCalcCell')
  .addItem('main', 'main')
  .addToUi();
}

function main() {
  var url = "###"; // Please put the endpoint with your token.

  var res = UrlFetchApp.fetch(url).getContentText(); // Modified
  var values = JSON.parse(res);
  var putData = values.result.map(function(e) {return [e.useragent, e.sg_event_id, e.timestamp, e.ip, e.url, e.event, e.keen.timestamp, e.keen.created_at, e.keen.id, e.url_offset.index, e.url_offset.type, e.sg_message_id, e.email]});
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("DATA");
  sheet.getRange(sheet.getLastRow() + 1, 1, putData.length, putData[0].length).setValues(putData);
}

注意:

  • 使用此功能时,请将包含令牌的端点放入url
  • 我在您的问题中使用JSON对象确认了此脚本。因此,如果更改对象的结构,则还需要修改脚本。请注意这一点。

参考:

如果我对您的问题有误解,请告诉我。我想修改它。

编辑1:

模式1:

var putData = values.result.map(function(e) {return [e.useragent, e.sg_event_id, e.timestamp, e.ip, e.url, e.event, e.keen.timestamp, e.keen.created_at, e.keen.id, JSON.parse(e["url_offset"]).index, JSON.parse(e["url_offset"]).type, e.sg_message_id, e.email]});

模式2:

var putData = values.result.map(function(e) {return [e.useragent, e.sg_event_id, e.timestamp, e.ip, e.url, e.event, e.keen.timestamp, e.keen.created_at, e.keen.id, e["url_offset"].index, e["url_offset"].type, e.sg_message_id, e.email]});

编辑2:

您能否运行此脚本并提供所创建文件的值?当然,请删除个人信息。但是请不要修改对象的结构。如果您做不到,我想考虑其他方法。

var url = "###"; // Please put the endpoint with your token.

var res = UrlFetchApp.fetch(url).getContentText();
DriveApp.createFile("sample.txt", res, MimeType.PLAIN_TEXT)

编辑3:

请将此脚本复制并粘贴到脚本编辑器中,运行myFunction()。然后,请显示文件的值。运行此功能时,请确认项目中是否存在不同的功能名称。

function myFunction() {
  var url = "###"; // Please put the endpoint with your token.
  var res = UrlFetchApp.fetch(url).getContentText();
  DriveApp.createFile("sample.txt", res, MimeType.PLAIN_TEXT)
}

编辑4:

请将此脚本复制并粘贴到脚本编辑器中,运行myFunction2()。然后,请显示结果。运行此功能时,请确认项目中是否存在不同的功能名称。

请确认是否检索到keenurl_offset的键和值。

function myFunction2() {
  var url = "###";
  var res = UrlFetchApp.fetch(url).getContentText();
  var values = JSON.parse(res);
  for (var key in values.result[0]) {
    Logger.log("key: %s, value: %s", key, values.result[0][key])
    if (typeof values.result[0][key] == "object") {
      for (var dkey in values.result[0][key]) {
        Logger.log("key: %s, dkey: %s, value: %s", key, dkey, values.result[0][key][dkey])
      }
    }
  }
}

编辑5:

请将此脚本复制并粘贴到脚本编辑器中,运行myFunction3()。然后,请显示结果。运行此功能时,请确认项目中是否存在不同的功能名称。

function myFunction3() {
  var url = "###"; // Please set this.
  var res = UrlFetchApp.fetch(url).getContentText();
  var values = JSON.parse(res);
  var obj = [];
  for (var i = 0; i < values.result.length; i++) {
    var temp = {};
    var v = values.result[i];
    for (var key in v) {
      temp[key.replace(/_/g, "")] = v[key];
      if (typeof v[key] == "object") {
        for (var dkey in v[key]) {
          temp[key.replace(/_/g, "") + dkey.replace(/_/g, "")] = v[key][dkey];
        }
      }
    }
    obj.push(temp);
  }
  var putData = obj.map(function(e) {return [e.useragent, e.sgeventid, e.timestamp, e.ip, e.url, e.event, e.keentimestamp, e.keencreatedat, e.keenid, e.urloffsetindex, e.urloffsettype, e.sgmessageid, e.email]});
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("DATA");
  sheet.getRange(sheet.getLastRow() + 1, 1, putData.length, putData[0].length).setValues(putData);
}

答案 1 :(得分:0)

看看您在这里做什么,通过Zapier集成以“仅追加”格式设计电子表格可能会容易得多。

Zapier能够直接处理SendGrid事件,如果需要的话,可以将这些事件附加到电子表格中。

然后,您可以将“计算列”放在电子表格的单独工作表中。

一个想法。