Я работаю в среде скриптов Google Apps, чтобы создать коннектор сообщества для Google Data Studio.Идея этого состоит в том, чтобы вызвать внешний API и проанализировать данные таким образом, чтобы Data Studio могла правильно читать диаграмму или таблицу из.
В настоящее время я пытаюсь уменьшить время загрузки, и ямы обнаружили, что наибольшее время занимает изменение ответа API с чего-то вроде ...
{
campaigns: [{
name_campaign: Example_Name,
ads: [
{cost: 15.98}
],
budget: 237.59
},
{
name_campaign: Another_Name,
ads: [
{cost: 98.25},
{cost: 13.03},
{cost: 23.44}
],
budget: 15.50
},
...
}
на то, что ожидает Data Studio, что является плоским набором данных ...
[
[237.59, Example_Name, 15.98],
[15.50, Another_Name, 98.25],
[15.50, Another_Name, 13.03],
[15.50, Another_Name, 23.44]
]
Хитрость в том, что, поскольку вызов API создается динамически, невозможно узнать, сколько будет полей или сколько будет различных объектов.Возможно, что есть только один объект с двумя полями или что-то похожее на описанное выше.К счастью, он был ограничен только родителями и детьми, а не братьями и сестрами.
Алгоритм до сих пор является нерекурсивным циклом, который находит самый глубокий объект и сохраняет все поля в последнем объекте / цикле.Если есть более глубокие объекты, то это повторяет этот процесс.Если нет, то он берет поля самого нижнего объекта и все ранее сохраненные поля, объединяет их вместе и добавляет их в виде строки, которую необходимо вернуть.Код также прокомментирован с помощью логики, которая, будем надеяться, будет полезна.
function stackIt(data) {
var totalData = [];
//create stack with highest object
var stack = [{
v: data,
parent_fields: []
}];
var stackLen = stack.length;
var pushing = 0, totalFields = 0;
var data_fields, array_field, cl, v, current_fields, temp, arr_len, row, parentFields;
while (stackLen > 0) {
//store current node
cl = stack.pop();
if (cl === undefined)
break;
v = cl.v;
parentFields = cl.parent_fields.slice(0);
//fill new array with all parents
data_fields = parentFields.slice(0);
array_field = null;
current_fields = [];
//Does another object exist?
//Keep track of all current fields on the chance that no objects exists below
for (var field in v) {
//Hold the current field
temp = v[field];
current_fields.push(temp);
//found an object. So we know we need to move deeper with the current object
if (typeof(temp) === 'object' && temp != null && array_field == null)
array_field = field;
//store current parent fields
if (typeof(temp) !== "object")
data_fields.push(temp)
}
//Push new node to stack to delve deeper
//each one with with parent data points to tack on later for deepest level objects
if (array_field != null) {
for (var i = 0, arr_len = v[array_field].length; i < arr_len; i++) {
//Skip broken fields
if ('errors' in v[array_field][i])
continue;
stack.push({
v: v[array_field][i],
parent_fields: data_fields
});
}
}
//No object exists below
else {
row = [];
//re set data fields if no object was found
//data_fields is changed in above function on the chance that there is an object below
data_fields = parentFields.slice(0);
//get total number of fields that should exist
//this is to prevent pushing rows with only a subset of fields
//only do once at deepest object to get total number of fields expected
if (pushing == 0) {
pushing = 1;
totalFields = data_fields.length + current_fields.length;
}
//push parents fields (ex. camp.cost)
row = data_fields.splice(0);
//push all current fields held (ex. keyword.cost)
row = row.concat(current_fields);
//comes out to camp.cost, keyword.cost
//Push all rows at lowest level; exit if done.
if (row.length != totalFields) {
console.log("End Stack");
return totalData;
}
else
totalData.push(row);
}
}
console.log("End Stack with empty stack");
return totalData;
}
Я пытался использовать библиотеку с открытым исходным кодом cFlatten
, но это делало уплощение намного медленнее, и большинство инструментов янайденные требуют только 1-2 объекта глубины и требуют специального форматирования для них.Раньше алгоритм был рекурсивным, но, поскольку объем возвращаемых данных настолько велик, он был намного медленнее.Будем весьма благодарны за любые идеи о том, как сделать функцию более быстрой / более эффективной.