Optimising Google Speed Insights API Script in Google Sheets - performance

I have created a script in Google Apps Scripts and Google Sheets that returns some speed metrics from the urls that are pasted in the sheet.
The script works good, the only problem is that it takes forever to present the results in the sheet. It makes a call for each url, I suspect that's why it's slow.
Is there any way I can optimise this script so it gives me the results faster?
Screenshot
The code:
const sheet = SpreadsheetApp.getActiveSpreadsheet();
const API_STRING = sheet.getSheetByName("instructions").getRange("K10").getValues();
const PLATFORM = sheet.getSheetByName("urls").getRange("B1").getValues();
const OUTPUT_CELL = sheet.getSheetByName("urls").getRange("B5:" + ("K" + sheet.getLastRow()));
console.log(PLATFORM);
// KPI
const lighthouseMetrics = [
"first-contentful-paint",
"largest-contentful-paint",
'interactive',
"cumulative-layout-shift",
"speed-index",
"total-blocking-time"
]
const fieldData = [
"FIRST_CONTENTFUL_PAINT_MS",
"LARGEST_CONTENTFUL_PAINT_MS",
"FIRST_INPUT_DELAY_MS",
"CUMULATIVE_LAYOUT_SHIFT_SCORE"
]
// CALLING FUNCTION
async function fetch_array() {
let URLS_LIST = sheet.getSheetByName("urls").getRange("A5:" + ("A" + sheet.getLastRow())).getValues();
console.log(URLS_LIST)
let arrayData = [];
for (let element of URLS_LIST) {
let dataEl = await getPageSpeedInfo(PLATFORM, element);
let dataRow = produceArray(dataEl);
arrayData.push(dataRow);
}
return OUTPUT_CELL.setValues(arrayData);
}
// PRODUCE ARRAY WITH KPIS
function produceArray(data) {
let kpiArray = [];
fieldData.forEach(function(item) {
let fieldDataRoute = data.loadingExperience.metrics[item].category;
kpiArray.push(fieldDataRoute);
})
lighthouseMetrics.forEach(function(item) {
let lighthouseRoute = data.lighthouseResult.audits[item].displayValue;
kpiArray.push(lighthouseRoute);
})
return kpiArray;
}
// CALL TO API
async function getPageSpeedInfo(strategy, element) {
let pageSpeedUrl = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=' + element + '&key=' + API_STRING + '&strategy=' + strategy;
console.log(pageSpeedUrl);
let response = await UrlFetchApp.fetch(pageSpeedUrl);
let data = await response.getContentText();
return JSON.parse(data);
}

Related

cannot read property "0" of undefined error

I have a code that pulls information from all excel type files in some folders on google drive. The problem is that there are over 100 files and the code only pulls data from around 30 files and shows the following error: "TypeError: Cannot read property '0' of undefined" The error is in line 12, "console.log(lista_carpetas_ok2[i][0]) // Here, you can see the folder ID in the log."
function listfechas() {
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var carpetasSheet = ss2.getSheetByName("carpetas");
var lista_carpetas = carpetasSheet.getRange("C2:C" + carpetasSheet.getLastRow()).getValues();
var lista_carpetas_ok2 = lista_carpetas.filter(([a]) => a);
var sheet2 = ss2.getSheetByName("SS23");
sheet2.clear();
sheet2.appendRow(["Folder", "Name", "SMS","rec SMS", "FIT", "rec FIT", "2FIT", "rec 2FIT" ,"3FIT" ,"rec 3FIT" ,"PP" ,"rec PP" ,"2PP" ,"rec 2PP", "3PP", "rec 3PP","SHIP", "rec SHIP", "2SHIP","rec 2SHIP"]);
for (var i = 0; i < 5; i++) {
console.log(lista_carpetas_ok2[i][0]) // Here, you can see the folder ID in the log.
var folderid = lista_carpetas_ok2[i][0];
try {
var parentFolder =DriveApp.getFolderById(folderid);
listFiles(parentFolder,parentFolder.getName())
listSubFolders(parentFolder,parentFolder.getName());
} catch (e) {
Logger.log(e.toString());
}
}
function listSubFolders(parentFolder,parent) {
var childFolders = parentFolder.getFolders();
while (childFolders.hasNext()) {
var childFolder = childFolders.next();
Logger.log("Fold : " + childFolder.getName());
listFiles(childFolder,parent)
listSubFolders(childFolder,parent + "|" + childFolder.getName());
}
}
function listFiles(fold,parent){
var data = [];
var files = fold.getFilesByType(MimeType.GOOGLE_SHEETS);
try {
while (files.hasNext()) {
var file = files.next();
var sms = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("A2").getValue();
var recsms = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("B2").getValue();
var fit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("C2").getValue();
var recfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("D2").getValue();
var dfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("E2").getValue();
var recdfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("F2").getValue();
var tfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("G2").getValue();
var rectfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("H2").getValue();
var pp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("I2").getValue();
var recpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("J2").getValue();
var dpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("K2").getValue();
var recdpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("L2").getValue();
var tpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("M2").getValue();
var rectpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("N2").getValue();
var ship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("O2").getValue();
var recship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("P2").getValue();
var dship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("Q2").getValue();
var recdship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("R2").getValue();
var fullRange = sheet2.getRange("A1:Z1001");
fullRange.setVerticalAlignment(DocumentApp.VerticalAlignment.TOP);
data = [
fold.getName(),
file.getName(),
sms,
recsms,
fit,
recfit,
dfit,
recdfit,
tfit,
rectfit,
pp,
recpp,
dpp,
recdpp,
tpp,
rectpp,
ship,
recship,
dship,
recdship,
];
sheet2.appendRow(data);
};
} catch (e) {
// In this modification, when your folder ID cannot be used, that folder ID is skipped. At that time, an error message can be seen in the log.
console.log(e.message);
}
}
}
When I wrote the code, I added catch (e) which I thought skipped the folder if there was no excel file in that folder, but the code stops at folder "QM0201" which does not have an excel file in it.
Does anybody know how I can fix it? I would like the code to run even if some folders don't have an excel files in them, those should just be skipped.
Thank you so much in advance! Any help is appreciated.
To avoid the error, replace
for (var i = 0; i < 5; i++) {
by
for (var i = 0; i < lista_carpetas_ok2.length; i++) {
This might also help to avoid the code to stop at certain folder.
Regarding the error
> Info Cannot read property 'getRange' of null"
This occurs because the spreadsheet hasn't a sheet named fechas
to avoid this error you might add
if(!SpreadsheetApp.open(file).getSheetByName("fechas")) break;
above of
var sms = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("A2").getValue();
if(
Debugging tips:
To verify that the correct values are assigned to lista_carpetas_ok2, add console.log(JSON.stringify(lista_carpetas_ok2)); just below lista_carpetas_ok2 declaration so you can review the values assigned to the variable.
To have more informative logs when an error occurs, instead of
} catch (e) {
Logger.log(e.toString()); // or console.log(e.message);
}
use
} catch (e) {
console.log(e.message, e.stack);
}
This is hardly a cause of the error but who knows, the code has the very unefficient part — 72 calls to the server. It can be greatly improved if you change this:
var sms = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("A2").getValue();
var recsms = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("B2").getValue();
var fit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("C2").getValue();
var recfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("D2").getValue();
var dfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("E2").getValue();
var recdfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("F2").getValue();
var tfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("G2").getValue();
var rectfit = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("H2").getValue();
var pp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("I2").getValue();
var recpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("J2").getValue();
var dpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("K2").getValue();
var recdpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("L2").getValue();
var tpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("M2").getValue();
var rectpp = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("N2").getValue();
var ship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("O2").getValue();
var recship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("P2").getValue();
var dship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("Q2").getValue();
var recdship = SpreadsheetApp.open(file).getSheetByName("fechas").getRange("R2").getValue();
To this:
var values = SpreadsheetApp.open(file).getSheetByName("fechas").getRange('A2:R2').getValues().flat();
var [sms,recsms,fit,recfit,dfit,recdfit,tfit,rectfit,pp,recpp,dpp,recdpp,tpp,rectpp,ship,recship,dship,recdship] = values;
It will reduce the quantity of calls to 4!
It should work faster and, if the real cause of the error is exceed of time limit (~6 min) this improvement can help. Try it.
Probably you could simplify the code further. Instead of this:
data = [
fold.getName(),
file.getName(),
sms,
recsms,
fit,
recfit,
dfit,
recdfit,
tfit,
rectfit,
pp,
recpp,
dpp,
recdpp,
tpp,
rectpp,
ship,
recship,
dship,
recdship,
];
You can use this:
var values = SpreadsheetApp.open(file).getSheetByName("fechas").getRange('A2:R2').getValues().flat();
var data = [fold.getName(), file.getName(), ...values];
No need to use the 18 variables, as far as I can see. It barely affects on the speed, though.

Google Apps Script to add links to google Spreadsheet adds 5000+ rows and i dont understand why?

Pretty self explanatory title, im trying to do a script where it takes the number on a column and uses that to search a list of files from google drive and then insert a link to that file.
HOWEVER, every time it inserts that link it also creates like 5000+ empty rows? why would this be?
The purpose is to take a number from a certain column, then look on google drive for the file that matches (at least partially) with that first number, then we should generate a link for that file and insert that link into another column, next to the number.
function CopiarResos() {
let ass = SpreadsheetApp.getActiveSpreadsheet();
let maxRows = ass.getSheetByName('set_de_datos_unificado').getMaxRows();
let columnaResos = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,2,maxRows,1);
let columnaLinks = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,53,maxRows,1);
let folder = DriveApp.getFolderById('1FJiet6tVgWXtM91Y7mmhgxDL2iYFm1VE'); // I change the folder ID here
let list = [];
let idList = [];
let files = folder.getFiles();
let match = '';
while (files.hasNext()){
file = files.next();
list.push(file.getName().toString());
idList.push(file.getId().toString());
}
console.log(list);
console.log(idList);
/*
let match = list.find(element => {
if (element.includes(substring)) {
return true;
}
});
*/
for (let i = 0; i in columnaResos; i++){
if(columnaLinks[i] == ""){
let substring = columnaResos[i];
match = list.find(element => {
if (element.includes(substring)) {
let idString = idList[i];
let insertStr = "https://drive.google.com/file/d/" + idString +"view";
let cellInsert = ass.getSheetByName('set_de_datos_unificado').getRange([i]+2,53);
cellInsert.setValue(insertStr);
return true;
}
});
}
};
}
getMaxRows() returns the number of rows that has the sheet (scroll down to the very bottom). You might delete the blank rows below your data or use getLastRow() instead.
References
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getmaxrows
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getlastrow
So, apart from all the thing wasnt written right turns out i was missing a bunch of lines! Mostly i was trying to get a fileid from an array even tho the indexes were completely unrelated (eg: trying to get list[300] instead of doing indexOf(match)
function copiarResos() {
let ass = SpreadsheetApp.getActiveSpreadsheet();
let maxRows = ass.getSheetByName('set_de_datos_unificado').getLastRow();
let columnaResos = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,2,maxRows,1);
let columnaLinks = ass.getSheetByName('set_de_datos_unificado').getSheetValues(2,53,maxRows,1);
let folder = DriveApp.getFolderById('1FJiet6tVgWXtM91Y7mmhgxDL2iYFm1VE'); // I change the folder ID here
let list = [];
let files = folder.getFiles();
let match = '';
while (files.hasNext()){
file = files.next();
list.push(file.getName().toString(), file.getId().toString());
}
console.log(list);
console.log(columnaLinks)
for (let i = 0; i in columnaResos; i++){
if(columnaLinks[i] == ''){
let substring = columnaResos[i];
match = list.find(element => {
if (element.includes(substring)) {
return true;
}
});
console.log(match);
matchId = list.indexOf(match);
if(matchId !== 0){
console.log(match + " id es" + matchId);
let idString = list[matchId+1];
console.log(idString)
let insertStr = "https://drive.google.com/file/d/" + idString +"/view?usp=sharing";
let cellInsert = ass.getSheetByName('set_de_datos_unificado').getRange(i+2 ,53);
cellInsert.setValue(insertStr);
}
}
match = ''
};
}

Google Users: List users data of a specific group

I am in the need of listing the users data belonging to a specific group within the organization. The documentation does not specify if this is possible. I was really hoping there could be some kind of query that would allow this. For example email in (1#domain.com,2#domain.com). However, I don't see that being possible. The only way I could think to accomplish this would be:
Get a list of all the members in the group (https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/list)
Get each user data by email (https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/get)
The problem with the above approach is that if a group contains 50+ members, this means that I have to make all that amount of requests, which is counter productive. Imagine how long that would take.
Any ideas? Greatly appreciate it.
Unfortunately I don’t think you can skip this two step process, but you can speed it up using batch requests. This
allows you to request up to 1000 calls in a single request. The steps would be:
Make a batch request to get all the members of all the groups you want (using members.list).
Make a batch request to get all the user info that you need using their id (using user.get).
Notice that the data in the result won’t be sorted, but they will be tagged by Content-ID.
References
Sending Batch Requests (Directory API)
Method: members.list (Directory API)
Method: users.get (Directory API)
I thought about the batching request a couple of hours after I posted the question. The problem with Node JS is that it does not has built in support for batch requests, unlike the php client library for example; Therefore, I had to spent some time implementing support for it on my own since I was not able to find any example. I'll share the solution in case it helps someone else or for my future reference.
async function getGroupMembersData(){
const groupEmail = "group#domain.com"; //google group email
const groupMembers = await getGroupMembers(groupEmail).catch(error=>{
console.error(`Error querying group members: ${error.toString()}`);
});
if(!groupMembers){ return; }
const url = "https://www.googleapis.com/batch/admin/directory_v1";
const scopes = ["https://www.googleapis.com/auth/admin.directory.user.readonly"];
const requests = [];
for(let i=0; i<groupMembers.length; ++i){
const user = groupMembers[i];
const request = {
email: user,
endpoint: `GET directory_v1/admin/directory/v1/users/${user}?fields=*`
};
requests.push(request);
}
const batchRequestData = await batchProcess(url, scopes, requests).catch(error=>{
console.error(`Error processing batch request: ${error.toString()}`);
});
if(!batchRequestData){ return; }
const usersList = batchRequestData.map(i=>{
return i.responseBody;
});
console.log(usersList);
}
//get group members using group email address
async function getGroupMembers(groupKey){
const client = await getClient(scopes); //function to get an authorized client, you have to implement on your own
const service = google.admin({version: "directory_v1", auth: client});
const request = await service.members.list({
groupKey,
fields: "members(email)",
maxResults: 200
});
const members = !!request.data.members ? request.data.members.map(i=>i.email) : [];
return members;
}
//batch request processing in groups of 100
async function batchProcess(batchUrl, scopes, requests){
const client = await getClient(scopes); //function to get an authorized client, you have to implement on your own
let results = [];
const boundary = "foobar99998888"; //boundary line definition
let batchBody = ""; const nl = "\n";
const batchLimit = 100; //define batch limit (max supported = 100)
const totalRounds = Math.ceil(requests.length / batchLimit);
let batchRound = 1;
let batchItem = 0;
let roundLimit = batchLimit;
do{
roundLimit = roundLimit < requests.length ? roundLimit : requests.length;
//build the batch request body
for(batchItem; batchItem<roundLimit; batchItem++){
const requestData = requests[batchItem];
batchBody += `--${boundary}${nl}`;
batchBody += `Content-Type: application/http${nl}`;
batchBody += `Content-Id: <myapprequest-${requestData.email}>${nl}${nl}`;
batchBody += `${requestData.endpoint}${nl}`;
}
batchBody += `--${boundary}--`;
//send the batch request
const batchRequest = await client.request({
url: batchUrl,
method: "POST",
headers: {
"Content-Type": `multipart/mixed; boundary=${boundary}`
},
body: batchBody
}).catch(error=>{
console.log("Error processing batch request: " + error);
});
//parse the batch request response
if(!!batchRequest){
const batchResponseData = batchRequest.data;
const responseBoundary = batchRequest.headers["content-type"].split("; ")[1].replace("boundary=", "");
const httpResponses = batchResponseParser(batchResponseData, responseBoundary);
results.push(...httpResponses);
}
batchRound++;
roundLimit += batchLimit;
} while(batchRound <= totalRounds);
return results;
};
//batch response parser
function batchResponseParser(data, boundary){
const nl = "\r\n";
data = data.replace(`--${boundary}--`,"");
const responses = data.split(`--${boundary}`);
responses.shift();
const formattedResponses = responses.map(i=>{
const parts = i.split(`${nl}${nl}`);
const responseMetaParts = (parts[0].replace(nl, "")).split(nl);
let responseMeta = {};
responseMetaParts.forEach(part=>{
const objectParts = part.split(":");
responseMeta[objectParts[0].trim()] = objectParts[1].trim();
});
const responseHeadersParts = parts[1].split(nl);
let responseHeaders = {};
responseHeadersParts.forEach(part=>{
if(part.indexOf("HTTP/1.1") > -1){
responseHeaders.status = part;
} else {
const objectParts = part.split(":");
responseHeaders[objectParts[0].trim()] = objectParts[1].trim();
}
});
const reg = new RegExp(`${nl}`, "g");
const responseBody = JSON.parse(parts[2].replace(reg, ""));
const formatted = {
responseMeta: responseMeta,
responseHeaders: responseHeaders,
responseBody: responseBody
};
return formatted;
});
return formattedResponses;
}

Can you use if statements in .nest(). If not what is the best way to assign labels to array elements so they fit in several groups

Is it possible to use if statements within .nest()? I'm trying to populate a column with several keys, but instead of looking for a name I want to assign a name/value to individual rows based on whether the value in the column is within a certain range of numbers. I have looked at the D3 Nest Tutorial and examples and I'm still having a hard time. This is the code I have at the moment, which isn't working. Any help would be greatly appreciated!
fireballData.forEach( d => {
years.forEach(year => {
const latitude = d['Latitude (deg.)'];
const impactEnergy = d['Calculated Total Impact Energy (kt)'];
const impactTest = +impactEnergy;
const impactLevel = nest('impactTest')
.key(function(d) { if (d.impactTest < .5) {return "impactA" }});
// .sortKeys(d3.ascending)
// .key(function(d) { return d.impactEnergy; })
// .sortKeys(function(a,b) {
// return impactEnergy.indexOf(a) - impactEnergy.indexOf(b); })
// .sortValues(function(a,b) { return ((a.who < b.who)
// ? -1
// : 1);;
const longitude = d['Longitude (deg.)'];
const impactYear = d['PeakBrightnessDate_TimeUT'];
const row = {
//year,
impactLevel,
impactEnergy,
latitude,
longitude,
impactYear
};
console.log(row);
});
});
Just to be a bit more clear, I want to assign five or six impact levels to the column impactLevel based on how big of a value impactEnergy is. This would then leave each row with the impactLevel id (ie impactLevel1) followed by the rest of data of that object. Any solustions or suggestions are great appreciated! I am still very new to d3 and I am still learning the in's and out's.
So for what I was trying to accomplish using .nest wasn't a good solution. The better way of going about creating the new array was to use .map.
export const loadAndProcessData = () =>
Promise
.all([
csv('data.csv')
])
.then(([fireballData]) => {
const minYear = 2015;
const maxYear = 2100;
const years = range(minYear, maxYear + 1);
const data = [];
// Special thanks to Darshit Shah for helping me figure this bit out
const showData = fireballData.map(d =>{
const impactYear = d['PeakBrightnessDate_TimeUT'];
const latitude = d['Latitude (deg.)'];
const longitude = d['Longitude (deg.)'];
const impactEnergy = +d['Calculated Total Impact Energy (kt)'];
const target = impactEnergy;
const type = 'Impact Year: ' + impactYear + ', Latitude: ' + latitude + ', Longitude: ' + longitude;
return {
sorce: (impactEnergy < 0.15 ? "0-0.15" : (impactEnergy < 0.25 ? "0.15-0.25" : (impactEnergy < 0.5 ? "0.25-0.5" : ">0.5"))),
target,
type
}
});
data.push(showData);
return data;
`

Last promise not fullfilled on first call

Here is some code, in a cloud function, on Parse-Server using promises.
It is supposed to be called once and do a certain job of removing some contents layed out in a tree stucture.
The problem is that I have to call the same code twice to get the job fully done.
If someone can take a look and say what is wrong, that will be very helpful.
Here is what happens, when the code is called for the first time. All the work is done, except the last removal.
That means the code from the line:
console.log("We finally remove the unit.");
and after is not executed.
When the code is run the second time, the last part is properly executed.
I may have done something incorrect with the promises, but I can't see what.
Parse.Cloud.define
("removeTheThing", function(request, response) {
var thingQuery;
thingQuery = .....;
.....
thingQuery.find().then
(function(resUnit) {
var secondLevelQuery;
secondLevelQuery = .....;
.....
secondLevelQuery.find().then
(function(resSentence) {
var thirdLevelQuery;
thirdLevelQuery = .....;
.....
thirdLevelQuery.find().then
(function(resTranslat) {
var fourthLevelQuery;
fourthLevelQuery = .....;
.....
fourthLevelQuery.find().then
(function(resExplain) {
var destroyPromises = [];
for (i = 0; i < resExplain.length; i++) {
destroyPromises.push(resExplain[i].destroy({}));
}
return Parse.Promise.when(destroyPromises);
}).then
(function() {
var destroyPromises = [];
for (iT = 0; iT < resTranslat.length; iT++) {
destroyPromises.push(resTranslat[iT].destroy({}));
}
return Parse.Promise.when(destroyPromises);
}).then
(function() {
var destroyPromises = [];
const s3 = new aws.S3();
for (iS = 0; iS < resSentence.length; iS++) {
// Let us remove the voice recording:
destroyPromises.push(s3.deleteObject({
Bucket: "londonspeak",
Key: resSentence[iS].get("audio")
}).promise());
destroyPromises.push(resSentence[iS].destroy({}));
}
return Parse.Promise.when(destroyPromises);
}).then
(function() {
console.log("We finally remove the unit.");
//return resUnit[0].destroy({});
//return Parse.Promise.when(resUnit[0].destroy({}));//Promise()
var destroyPromise = [];
destroyPromise.push(resUnit[0].destroy({}));
return Parse.Promise.when(destroyPromise);
}).then(response.success);
});
});
});
});

Resources