So I have a script (google apps script) that pulls data from one of my sheets (to pairs: initials && percentage) that has changing values (sometimes it's only weekly other times it's daily).
It's supposed to check the old values against the new values and only process the new values, but it's processing for all values for some reason.
During the loop process it starts by finding the email attached to that cell and then sends a generated email to the person. Then at the end it stores the new values found over the previous.
Getting New Data & Variables
var data = dataRange.getValues(); // Fetch values for each row in the Range.
var oldData = [{}];
//Declare variable
Getting Old Data from document properties.
var oldValues = PropertiesService.getDocumentProperties().getProperties();
//get values from document properties
var outerArrayOldData = [];
//empty array
var arr4 = [];
//empty array
var thisLoopString,
thisRowArray;
for (var key in oldValues) {
//grabbing keys from document properties 'row[i]' and loop for each
thisLoopString = oldValues[key];
thisRowArray = []; //Reset
array
thisRowArray = thisLoopString.split(","); //Convert the string to partial array
arr4.push(thisRowArray); //Push the inner array into the outer array
outerArrayOldData = arr4.concat(outerArrayOldData); //convert outer to actual usable array
var arr4 = []; //reset arr4 back to 0
};
//End getting old data
Comparing old data to new data
var oldData = outerArrayOldData;
var source = oldData.map(function (row) {
return JSON.stringify(row);
//map array to string
}),
searchRow,
dataLength = data.length;
for (i = 0; i < dataLength; i += 1) {
searchRow = JSON.stringify(data[i]);
if (source.indexOf(searchRow) == -1) {
//search old data and compare to new data using index search and if data isn't in old stack process it through functions
//doing stuff with new pairs
}
}
}
}
How old data is stored to Doc properties.
var objOldData = {};
//empty
var keyName = "",
//empty
thisRowArray;
for (i = 0; i < data.length; i++) {
keyName = "row" + (i).toString();
//set keys
thisRowArray = data[i].toString();
//convert each pair array to string
if (thisRowArray == "") continue;
//skip blanks
objOldData[keyName] = thisRowArray;
//add keys and values to properties as a string
}
PropertiesService.getDocumentProperties().setProperties(objOldData,
true); //true deletes all other properties
//Store the Updated/New Values back to Properties
}
Logger Console:
<<<<<<<<Imported Range data>>>>>>>>
[[BBB, 0.9], [CCC, 0.76], [DDD, 0.89], [, ]]
<<<<<<<<Old data from dpcument properties>>>>>>>>
[[DDD, 0.89], [, ], [BBB, 0.9], [CCC, 0.76]]
<<<<<Processing New Values Not in Old Data>>>>>
[CCC, 0.76]
[BBB, 0.9]
[DDD, 0.89]
<<<<<<<<Store the Updated/New Values back to Properties>>>>>>>>
{row1=CCC,0.76, row0=BBB,0.9, row3=,, row2=DDD,0.89}
As you can see it's still processing all the values even though they are not new and already exist in the system. How come the search isn't finding that they already exist? WHere did I go wrong on this?
In your "Comparing old data to new data" for loop code, try changing:
searchRow = JSON.stringify(data[i]);
to:
searchRow = JSON.stringify([data[i][0], data[i][1].toString()]);
This ensures that the value at the second array index is always converted into a string for comparison to the "old" imported value, which appears to be parsed from a row delivered as a string.
It looks like, currently, new data array values declared with the second value as numeric, (or perhaps null or empty value):
[["BBB", 0.9], ["CCC", 0.76], ["DDD", 0.89], ["",""]];
While "old" rows (imported from Google doc) are imported and converted into an array, where the values are strings:
[["CCC","0.76"],["BBB","0.9"],["",""],["DDD","0.89"]]
On comparing rows with JSON.stringify, for example, '["DDD","0.89"]' does not match '["DDD",0.89]', so all rows are getting erroneously registered as "new".
I did a bit of guessing from your example to arrive at this, but it could be the cause of your bug. Good luck!
I have trouble understanding your code, so I created my own instead:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = {};
function getData() {
var range = sheet.getRange("A1:B3");
var values = range.getValues();
for (var i=0; i < values.length; i++) {
var key = 'row' + i;
var currentRow = values[i];
// for each cell value,
// toString : convert to string
// trim : remove all whitespaces from both ends of cell values
// encode… : encode the values so we don't have any ","
var arr = currentRow.map(function(v){return encodeURIComponent(v.toString().trim())});
// join the array with "," delimiter
var s = arr.join();
data[key] = s;
}
} // getData()
function saveData() {
getData();
PropertiesService.getDocumentProperties().setProperties(data);
}
function compareData() {
getData();
var props = PropertiesService.getDocumentProperties().getProperties();
for (var idx in props) {
if (idx in data) {
if (data[idx] != props[idx]) {
Logger.log('\n%s is different\nOld value is "%s"\nNew value is "%s"',
idx,
decodeURIComponent(props[idx]),
decodeURIComponent(data[idx]));
}
} else {
Logger.log('missing row: ' + idx);
}
}
}
// Test function. Check all document properties
function peekProperties() {
var props = PropertiesService.getDocumentProperties().getProperties();
for (var idx in props) {
Logger.log('%s = %s', idx, props[idx]);
}
}
Question: what if a row is deleted? Shouldn't key be the value in A column instead of row number?
Related
I'm developing a tool and currently I'm stuck with a problem.
I'm writing a code in GoogleAppScript (JavaScript) and I have two columns where I collect data. As a result I've two arrays. Let's call them mainArray and checkArray
I need a code doing this logic:
getting the 1st value of the mainArray, i.e. mainArray[0]
chenking the value if it's equal to checkArray[0], then checkArray[1]... checkArray[i]
if there's a match, then toss it to the garbage bin, and swith to the mainArray[1]
Checking mainArray[1] with all of the values from checkArray, as we did it in p.2
If there's no match with any vals from the checkArray add these value into the 3rd array (finArray)
I've done exaclty the opposite.
for (var j=0; j<checkArr.length; j++) {
for(var i=0; i<mainArr.length; i++) {
if(mainArr[i][0]!==''){
if(checkArr[j][0]==mainArr[i][0])
{
Logger.log('not in the list'+mainArr[i][0])
finArr.push(mainArr[i][0])
break;
}}
But I don't know how to get the code working as I described above.
`
// The Arrays actually are one dimensional
// I prefer to create a one dimensional array
// GetDataArray function creates one dimensional array
function GetDataArray(sht,rng) {
var Data = [] var i = 0;
Logger.log(' Sht Name %s\n rng %s,', sht.getName(), rng)
sht.getRange(rng).getValues() .forEach(
function (row) {
row.forEach( function (cell) {
//Logger.log(cell);
Data[i++] = cell }); } );
return Data
} //
......
var sht = SpreadsheetApp.getActiveSheet()
var rngMain = ....// Provide the range
var rngCheck = ...
var checkArr = GetDataArray(sht, rngCheck)
var mainArr = GetDataArray(sht, rngMain)
var finArr = []
mainArr.forEach( function(cell) {
if (cell == '') continue
if (checkArr.indexOf(cell) != -1) finArr.push(cell)})
function thefunc() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
let vs1 = sh.getRange(1,1,sh.getLastRow(),1).getValues().flat();
let vs2 = sh.getRange(1,2,sh.getLastRow(),1).getValues().flat();
let d = 0;
vs1.forEach((r,i) => {
if(~vs2.indexOf(r[0])) {
sh.deleteRow(i+1-d++);//delete row
}
});
}
I am facing an issue when populating an array of the object dynamically in javascript. I have this sample data as below:
I have to populate following arrays with the data from above:
c1_Arr = [];
c2_Arr = [];
var torontoObj = { arName: 'تورونتو', enName: 'Totonto', value: 0 };
var parisObj = { arName: 'باريس', enName: 'Paris', value: 0 };
var londonObj = { arName: 'لندن', enName: 'London', value: 0 };
Now I am looping through the data to set the values from data as:
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++) {
var data = results.features[i].attributes;
parisObj.value = data.Paris;
londonObj.value = data.London;
torontoObj.value = data.Toronto;
if (data.Ind_ID === 101) {
c1_Arr.push(parisObj);
c1_Arr.push(londonObj);
c1_Arr.push(torontoObj);
}
}
console.log(c1_Arr);
I am getting this data in console:
Here I am getting the values of the object i.e. Ind_ID = 102 instead of the object values of Ind_ID = 101 (first object).
How to get the values of the required object using the Ind_ID?
The problem is because even though you have the if condition there but you are updating the value of the objects in the loop and since you have already pushed them objects you still have the reference in the main objects. They get overwritten.
Create the 3 objects (torontoObj, etc.) inside the loop.
Reference is getting updated in the second iteration (where Ind_ID is 102)
You should rather do
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++) {
var data = results.features[i].attributes;
if (data.Ind_ID === 101) {
parisObj.value = data.Paris;
londonObj.value = data.London;
torontoObj.value = data.Toronto;
c1_Arr.push(parisObj);
c1_Arr.push(londonObj);
c1_Arr.push(torontoObj);
}
}
console.log(c1_Arr);
Your object values are getting updated even after being set inside the if loop, simply because, you're not limiting it from being updated.
You could probably do one of the following 2 things:
The simpler one:
Extract the values of Paris, London and Toronto fields of data only if the Ind
_ID is 101.
like this:
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++) {
var data = results.features[i].attributes;
if (data.Ind_ID === 101) {
parisObj.value = data.Paris;
londonObj.value = data.London;
torontoObj.value = data.Toronto;
c1_Arr.push(parisObj);
c1_Arr.push(londonObj);
c1_Arr.push(torontoObj);
}
}
console.log(c1_Arr);
The more elegant one:
Extract the array element which only matches your condition, in other words filter.
var resultCount = results.features.length;
var data = results.features.filter(feature => feature.attributes.Ind_ID === 101);
parisObj.value = data[0].Paris;
londonObj.value = data[0].London;
torontoObj.value = data[0].Toronto;
console.log(c1_Arr);
For a project, I need to do some data manipulation in JavaScript.
I need to convert this object:
[
{"source":"stkbl0001","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0003","target":"stkbl0005"},
{"source":"stkbl0004","target":"stkbl0005"},
{"source":"stkbl0004","target":"stkbl0005"}
]
to this object:
[
{"source":"stkbl0001","target":"stkbl0005","value":1},
{"source":"stkbl0002","target":"stkbl0005","value":5},
{"source":"stkbl0003","target":"stkbl0005","value":1},
{"source":"stkbl0004","target":"stkbl0005","value":2}
]
(notice that some elements in the first object are same and new field value contains number of repeats)
Basically, I need to detect and count multiple instances, and to create new field value that contains number of instances.
How do I do that?
You can keep track with an object:
var obj = {};
var result = [];
for (var i = 0; i < arr.length; i++) {
var item = arr[i],
key = item.source + '-' + item.target;
if (obj.hasOwnProperty(key)) obj[key].value++;
else {
obj[key] = item;
item.value = 1;
}
}
for (var prop in obj) {
result.push(obj[prop]);
}
In this example, arr is assumed to be your original array, and result is your resulting array.
result will end up being an array of objects that have unique combinations of source and target properties, and value will be the number that those combinations were encountered.
I'm trying to save certain JSON values to JS array.
var count = Object.keys(item.programme).length; // item is JSON file, count is 23
for (i=0; i<count; i++) {
var title = item.programme[i].title.de;
console.log(typeof title); //string
console.log(title); // desired values, title when i
listData = [];
listData[i] = title;
}
console.log(listData); // [undefined, undefined,.....,title when i =22]
I would like to get array of values from title variable. I get desired value only in last field of array, rest is undefined.
It is kind of trivial. You define listData in each iteration. Move it outside the loop:
var listData = [];
for (var i=0; i<count; i++) {
...
listData[i] = title;
}
I have a question about manipulating JSON data using Javascript and stringify/parse. In the below example, I create a JSON string, then use parse to convert it back into an object. After doing that, what I want to do is delete an item with a certain ID, and the only way I can find to do it is to loop through the entire array and delete the element from the array once I find a match. This doesn't seem very efficient. Is there a better way to do this?
var employees = [];
//build the array
for (var i=0; i < 10; i++) {
var player = { "id": i, "salary": i*1000000 };
employees.push(player);
}
json_employees = JSON.stringify({employees: employees}); //convert to json string
alert(json_employees); //display the new string
var obj = JSON.parse(json_employees); //convert back to a Javascript object
for (var j=0; j < obj.employees.length; j++) { // loop through the array
if (obj.employees[j].id === 5) // is it the employee with id 5?
obj.employees.splice(j, 1); // remove the fifth item
}
json_modified_employees = JSON.stringify({employees: obj.employees}); //convert back to json string
alert(json_modified_employees); //display the new string
You could store the employees in an object, with a key of their id, something like this:
// create a store object
var employees = {};
//build the array
for (var i=0; i < 10; i++) {
var player = { "id": i, "salary": i*1000000 };
// add item to store object with a key of 'pk' + i
employees['pk' + i] = player;
}
json_employees = JSON.stringify({employees: employees}); //convert to json string
alert(json_employees); //display the new string
var obj = JSON.parse(json_employees); //convert back to a Javascript object
// remove the required item (in this case number 5)
delete obj.employees['pk' + 5];
json_modified_employees = JSON.stringify({employees: obj.employees}); //convert back to json string
alert(json_modified_employees); //display the new string
If you then wanted to iterate over your employees, you would
for (var key in employees) {
if (employees.hasOwnProperty(key)) {
alert(employees[key].id)
}
}