Google sheet script to match and copy based from another adjacent cell - javascript

I am trying to look for matching cells in column R,T,and V in the reference table with column C in the main sheet. If there is a match then copy the assigned number in Q,S, and U and past it in column B next to the its match.
I have done the example manually.

Suggestion
Perhaps you can try this sample script:
Script [UPDATED]
function findMatch() {
var sh = SpreadsheetApp.getActiveSpreadsheet();
var lastRow = sh.getDataRange().getLastRow();
var reference = [];
var row = 1;
var data = sh.getRange("Q1:V"+lastRow).getDisplayValues().filter(function(x) {
return (x.join('').length !== 0);
});
sh.getRange("C1:C"+lastRow).getDisplayValues().forEach( x => {
reference.push([fixForUsage(x),row]);
row += 1;
});
reference.forEach(aisle => {
if(aisle[0] == "" || aisle[0].toString().toLowerCase().includes("aisle"))return;
data.forEach(match => {
var currentData = match[1] +"-"+match[3]+"-"+match[5];
if(currentData.includes(aisle[0])){
//get its number
if(match[1] == ""){
if(match[3] == ""){
if(match[5] == ""){
}else{
//if not empty
Logger.log("Find \""+aisle[0]+"\" from sheet row#"+aisle[1]+"\nRESULT:"+"\nFound a match on these data!: "+match+"\nHeader: \'"+data[0][4]+"\'\nNumber: "+match[4]);
pasteData(sh,aisle[1], data[0][4], match[4]);
}
}else{
//if not empty
Logger.log(+"Find \""+aisle[0]+"\" from sheet row#"+aisle[1]+"\nRESULT:"+"\nFound a match on these data!: "+match+"\nHeader: \'"+data[0][2]+"\'\nNumber: "+match[2]);
pasteData(sh,aisle[1],data[0][2],match[2]);
}
}else{
//if not empty
Logger.log("Find \""+aisle[0]+"\" from sheet row#"+aisle[1]+"\nRESULT:"+"\nFound a match on these data!: "+match+"\nHeader: \'"+data[0][0]+"\'\nNumber: "+match[0]);
pasteData(sh,aisle[1],data[0][0],match[0]);
}
}
});
});
}
function pasteData(sh,row, colAData, colBData){
sh.getRange("B"+row).setValue(colBData);
sh.getRange("A"+row).setValue(colAData);
}
function fixForUsage(x){ //This is to let the code know that e.q. 53-7 is 53-07
var part = x.toString().split("-");
if(part.length == 2 && part[1].length == 1){
return part[0]+"-0"+part[1];
}else{
return x;
}
}
Sample Sheet
Columns A, B, C:
Columns Q, R, S, T, U, V:
Sample Demonstration
After running the script from the Apps Script editor:
Apps Script editor log results for review:

Here is another solution (updated):
function myFunction() {
var sh = SpreadsheetApp.getActiveSheet();
// get all data
var data = sh.getRange('q2:v16').getDisplayValues();
var cols_QR = data.map(x => ({'crane': 'C5-1', 'seq': x[0], 'aisle': x[1]}));
var cols_ST = data.map(x => ({'crane': 'C5-4', 'seq': x[2], 'aisle': x[3]}));
var cols_UV = data.map(x => ({'crane': 'C5-2', 'seq': x[4], 'aisle': x[5]}));
data = [...cols_QR, ...cols_ST, ...cols_UV];
data = data.filter(x => x.aisle != '');
data.forEach((x,i) => data[i].aisle = fix(x.aisle)); // <--- new line
// create the object 'aisles'
var aisles = {}
for (let obj of data) aisles[obj.aisle] = {'crane': obj.crane, 'seq': obj.seq}
// get target range and target data
var target_range = sh.getRange('a2:c' + sh.getLastRow());
var target_data = target_range.getDisplayValues();
// fill target range with info from the 'aisles' object
for (let row in target_data) {
try {
let orig_key = target_data[row][2]; // <--- updated line
let key = fix(orig_key); // <--- new line
target_data[row] = [ aisles[key].crane, aisles[key].seq, orig_key ]; // <--- updated line
} catch(e) {}
}
// fill the target range with updated data
target_range.setValues(target_data);
}
// function to convert '10-1 1/4' --> '10-01', '8-0' --> '08-00', etc
function fix(key) {
return key.split(' ')[0]
.split('-').map(x => x.length == 1 ? '0' + x : x)
.join('-').slice(0,5);
}
Initial data:
Results:
Sheet
I decided don't add in my variant the function that makes true this: '53-7' == '53-07' and '11' == '11-0', etc, because I think it's a rather bad and error-prone idea. It will silently hide many errors in your data. But I can add it if you want.
Update
The function can be something like this:
function fix(key) {
return key.split(' ')[0]
.split('-').map(x => x.length == 1 ? '0' + x : x)
.join('-').slice(0,5);
}
// test
const keys = ['10-1 1/4', '11-0', '9-11 1/2', '8-0', '53-06', '52-7', '53-07', '104', '8-02-S', '08-01'];
keys.forEach(key => console.log(fix(key) + ' <--- ' + key));
I've added the function fix() and several lines to my original code.
But actually functions like this can cause additional troubles. For example I have no idea what means '104'? If it should be '10-04'? Or may be '01-04'? Or something else? You need be well prepared if you decide to play the risky game.
Note: you can change orig_key to key in this line:
target_data[row] = [ aisles[key].crane, aisles[key].seq, orig_key ];
This way you will get the 'fixed' values in the target table instead of original ones.

Related

Method search on google sheet data from one column using google script?

I had tried to search data like below flow picture and script to search data from google sheet using google app script but the script using is not working properly but can someone tell me how to setup search function to find data like flow on image? thanx
[Flow searching data][1]
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "Search", functionName: "searchRecord"} ];
ss.addMenu("Commands", menuEntries);
}
function searchRecord()
{
var ss = SpreadsheetApp.getActiveSpreadsheet()
var wsSearchingData = ss.getSheetByName("Searching Data")
var wsDatabase = ss.getSheetByName("Database")
var searchString = wsSearchingData.getRange("E4").getValue();
var column =1; //column Index
var columnValues = wsDatabase.getRange(2, column, wsDatabase.getLastRow()).getValues(); //1st is header row
var searchResult = columnValues.findIndex(searchString); //Row Index - 2
var searchValue = wsDatabase.getRange("B2:B2041").getValues()
var matchingDatabase = searchValue.map(searchColumn => {
var matchColumn = columnValues.find(r => r[0] == searchColumn[0])
return matchColumn = matchColumn ? [matchColumn[2]] : null
})
console.log(matchingDatabase)
if(searchResult != -1)
{
//searchResult + 2 is row index.
SpreadsheetApp.getActiveSpreadsheet().setActiveRange(sheet.getRange(searchResult + 1, 1))
}
Array.prototype.findIndex = function(search){
if(search == "") return false;
for (var i=0; i<this.length; i++)
if (this[i] == search) return i;
wsSearchingData.getRange("B11").setValue(search[0]);
wsSearchingData.getRange("C11").setValue(search[1]);
wsSearchingData.getRange("D11").setValue(search[2]);
wsSearchingData.getRange("E11").setValue(search[3]);
wsSearchingData.getRange("F11").setValue(search[4]);
return;
}
}
[1]: https://i.stack.imgur.com/HF9K8.png
var searchResult = columnValues.findIndex(searchString); //Row Index - 2
replace the above code with:
var searchResult = columnValues.filter(r=>r[1]==searchString)
You can then put searchResult directly as output in the sheet. Make sure that [1] in the above contains the column index of Name in the columnValues Array.

GAS Function not setting value as intended in sheet

This is the Google Sheet, it can be copied: https://docs.google.com/spreadsheets/d/1ffIRGiGkiy5WFzSAvWNOY_3cqNXgTAOtO6o8vxS-BFU/edit?usp=sharing
The Function 'AddNewMembers' does not function, even if "isAdded == "No" it will not setValue(recruit_id)
function AddNewMembers(event){
event = {range: SpreadsheetApp.getActiveRange()}
CheckHandleSteamIDNotation(event)
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var recruitment_log = ss.getSheetByName('RL1');
var main_roster = ss.getSheetByName('Main Roster');
var isAdded = recruitment_log.getRange('R3').getValue();
if(isAdded == "No") {
var recruit_id = "'" + recruitment_log.getRange('J3').getValue();
main_roster.getRange('I100').setValue(recruit_id);
}
}
function CheckHandleSteamIDNotation(event)
{
let formSheet = SpreadsheetApp.getActiveSheet();
let header = formSheet.getRange(1,1,1,formSheet.getMaxColumns()).getValues();
let formRange = formSheet.getRange(formSheet.getLastRow(), 1, 1, formSheet.getMaxColumns());
let formValues = formRange.getValues();
for(let i = 0; i < header[0].length; i++)
{
if(header[0][i].includes("SteamID"))
{
formValues[0][i] = "'" + formValues[0][i];
}
}
formRange.setValues(formValues);
}
Since the provided script above contains var isAdded = recruitment_log.getRange('R3').getValue(); the value of R3 is currently set to "Yes" that is why the condition for the script below is not running.
if(isAdded == "No") {
var recruit_id = "'" + recruitment_log.getRange('J3').getValue();
main_roster.getRange('I100').setValue(recruit_id);
}
Try this modification:
function AddNewMembers(event) {
event = { range: SpreadsheetApp.getActiveRange() }
CheckHandleSteamIDNotation(event)
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var recruitment_log = ss.getSheetByName('RL1');
var main_roster = ss.getSheetByName('Main Roster');
//Gets all the data values on recruitment_log
var isAdded = recruitment_log.getRange(3, 1, recruitment_log.getLastRow(), recruitment_log.getLastColumn()).getValues();
//Gets the last row starting I17
var lastrow = main_roster.getRange(17, 9, main_roster.getLastRow() , 1).getValues().filter((x => x > 1)).length
//Sets the value on the last blank row
isAdded.map(x => x[17].toString().toLocaleLowerCase() == "no" ? "'" + main_roster.getRange(17 + lastrow,9).setValue(x[9]) : x)
}
I made modifications on your isAdded variable to the following to get the entire range of data on RL1 sheet.
var isAdded = recruitment_log.getRange(3, 1, recruitment_log.getLastRow(), recruitment_log.getLastColumn()).getValues();
This part of script was only used to get the current length of data for the New Operatives. Using .filter() method to filter out empty array elements, since getValues() gets blank cells if there is formatting applied on the spreadsheet.
var lastrow = main_roster.getRange(17, 9, main_roster.getLastRow() , 1).getValues().filter((x => x > 1)).length
Using ES6 .map() method to create a new array for the data that hasn't been added to the main roster sheet file.
isAdded.map(x => x[17].toString().toLocaleLowerCase() == "no" ? "'" + main_roster.getRange(17 + lastrow,9).setValue(x[9]) : x)
Screenshot:
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#description

How to compare a value with each item of range

for the last 3 days (my first 3 days of coding) i've been trying to code an script to get my google contacts that have certain keyword, it being "Catamarca", on their name and also to delete that keyword after they've been added to the spreadsheet leaving only their name.
I've been succesfull in all of this. But now i want to only run the script on an existing database, and only run it if the new contacts are not on the sheet already, and not write over the existing ones.
Here is my code so far:
function impContacts() {
// variables
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("GContacts");
var grupo = ContactsApp.getContactGroupById("http://www.google.com/m8/feeds/groups/email#gmail.com/base/6")
const contactos = grupo.getContacts();
const arraycontacts = [];
// get the last row on B with data on it
const lastRow = sheet.getLastRow();
const Avals = sheet.getRange("B2:B" + lastRow).getValues();
const Alast = lastRow - Avals.reverse().findIndex(c => c[0] != '');
Logger.log(Alast);
var rangeInteres = sheet.getRange(2, 1, Alast, sheet.getLastColumn()).getValues();
// look for contacts that has in their name the word "Catamarca", and save them with their id, name and phone.
contactos.forEach(contacto => {
var phone = ""
if (contacto.getPhones()[0]) {
phone = contacto.getPhones()[0].getPhoneNumber()
};
var name = ""
if (contacto.getFullName().match("Catamarca")){
name = contacto.getFullName();
};
var idcont = ""
if (name == rangeInteres.forEach(namme =>
{
oldName = namme[1];
Logger.log(oldName);}))
{
idcont =
rangeInteres.forEach(id => {
oldId= id[0];
Logger.log(oldId);})
}
else
{
idcont = contacto.getId().replace(/\D/g, '')
};
const datoscont = [idcont, name, phone];
arraycontacts.push(datoscont);
})
// save new contact
sheet.getRange(2, 1, arraycontacts.length, 3).setValues(arraycontacts);
// look for "catamarca"
range = sheet.getRange("B2:B")
var textFind = range.createTextFinder("Catamarca");
textFind.matchEntireCell(false);
textFind.ignoreDiacritics(true);
textFind.matchCase(false);
var textFound = textFind.findNext();
// Si encuentra coincidencia reemplazar por ""
if (textFound !== null) {
var vals = textFound.getValues();
textFind.replaceAllWith("");
}
}
What i need to keep the most is the ID of the existing contacts (the IDs are different from the ones coming from google contacts but the names are the same), because they are linked to an app created using AppSheet.
I believe there should be a way to accomplish this by editing this part of the code
var idcont = ""
if (name == rangeInteres.forEach(namme =>
{
oldName = namme[1];
Logger.log(oldName);}))
{
idcont =
rangeInteres.forEach(id => {
oldId= id[0];
Logger.log(oldId);})
}
else
{
idcont = contacto.getId().replace(/\D/g, '')
};
In my head and with my current knowledge, the code should be working, but it's not, I mean, it runs, but overwrites everything.

combine duplicate rows in apps script

Current sheet
Required sheet
I have an addon that combines duplicate rows, but I want apps script to run onEdit trigger.
Here is the script:
const HDR = 1 // header height
const GROUP_COL = 1 // in which column is the grouping value
function onEdit(e){
// we are interested only if value is not empty and the content of colum GROUP_COL has been changed
if(!e.value || e.value===e.oldValue || e.range.columnStart!==GROUP_COL || e.range.rowStart<=HDR){
return
}
const sh = SpreadsheetApp.getActiveSheet()
const values = sh.getDataRange().getValues().slice(HDR-1)
const existingRows = values.map((r,i)=>({ row:HDR+i, cells:r, found:r[GROUP_COL-1]==e.value })).filter(x=>x.found)
console.log(existingRows)
if(existingRows.length===0){
return
}
const destRange = sh.getRange(e.range.rowStart,1,1,existingRows[0].cells.length)
const destRow = destRange.getValues()[0]
// merge content into the new row
existingRows.forEach(er=>{
er.cells.forEach((c,i)=>{
if(i===GROUP_COL-1 || er.row===e.range.rowStart){
return
}
destRow[i] = (destRow[i] + "\n" + er.cells[i]).trim()
})
})
destRange.setValues([destRow])
// delete extra rows
existingRows.forEach((er,i)=>{
if(er.row!==e.range.rowStart){
sh.deleteRow(er.row-i)
}
})
}

Javascript check if url param exists

I'm running an A/B test to see if showing more items is better for conversion. But it seems that the code sometimes causes errors.. But I can't find any errors and don't know when they occur.
In my test I check whether the url param IC exists and if it doesn't exists I will add this.
This is my code:
function checkIfAlreadyPaginated()
{
var field = 'IC';
var url = window.location.href;
if(url.indexOf('?' + field + '=') != -1)
return true;
else if(url.indexOf('&' + field + '=') != -1)
return true;
return false;
}
function insertParam(key, value) {
key = encodeURIComponent (key); value = encodeURIComponent (value);
var kvp = document.location.search.substr(1).split('&');
if (kvp == '') {
return '?' + key + '=' + value;
}
else {
var i = kvp.length; var x; while (i--) {
x = kvp[i].split('=');
if (x[0] == key) {
x[1] = value;
kvp[i] = x.join('=');
break;
}
}
if (i < 0) { kvp[kvp.length] = [key, value].join('='); }
return '?'+kvp.join('&');
}
}
var itemsPerPage = 48;
if(!checkIfAlreadyPaginated())
{
document.location.search = insertParam('IC', itemsPerPage);
}
Does someone spot possible issues? I'm running the test via VWO.com.
If there is a Javascript error you should see it in the browser console and share it with us.
In any case, I would do it by creating a JS Object first. I find it easier to work with.
In the following code I added the option to do the checking for multiple params of the querystring. If you only need to check the IC you can simplify it a bit. I tested it on a blank test.html.
<script type="text/javascript">
// get the current params of the querystring
var querystringItems = document.location.search.substr(1).split('&');
// create an object
var querystringObject = {};
for(i=0;i<querystringItems.length;++i) {
param = querystringItems[i].split('=');
querystringObject[param[0]] = param[1];
}
// Define the keys to be searched for and their default value when they are not present
var requiredKeys = {"IC":48, "test": "me"};
// Do the checking on the querystringObject for each requiredKeys
var doreload = false;
for (var key in requiredKeys) {
if (typeof querystringObject[key] == 'undefined') {
doreload = true;
// Create the missing parameter and assign the default value
querystringObject[key] = requiredKeys[key];
}
}
// If any of the requiredKeys was missing ...
if (doreload) {
// rebuild the querystring
var querystring = '?';
for (var key in querystringObject) {
querystring+=key+'='+querystringObject[key]+'&';
}
querystring=querystring.substr(0,querystring.length-1);
// reload page
document.location.search = querystring;
}
// assign the values to javascript variables (assuming you had it like this because you needed it)
var itemsPerPage = querystringObject.IC;
</script>
Here is an example to check this:
//get URL params into string:
paramStr = window.location.substring(window.location.indexOf('?'), window.location.length;
//turn string into array
paramArray = paramStr.split('&');
//prepare final array of params
params = {};
//prepare the index of IC parameter
icLoc = -1; //this is negative 1 so that you know if it was found or not
//for each item in array
for(var i in paramArray){
//push its name and value to the final array
params.push(paramArray[i].split('='));
//if the parameter name is IC, output its location in array
if(params[i][0] === 'IC'){
icLoc = i;
}
}
If IC is not found, icLoc will be -1.
If it is found, the value of IC in the URL parameters is params[icLoc][1]
Example result for query string ?foo=bar&code=cool&IC=HelloWorld:
params = {'foo': 'bar', 'code': 'cool', 'IC': 'HelloWorld'}
icLoc = 2
Example for query string ?foo=bar&code=cool:
params = {'foo': 'bar', 'code': 'cool'}
icLoc = -1
Here id is the param I'm using for a test. Pass the argument which you want to check whether it exists or not.
function queryParamExistUrl(param = '') {
if (new URLSearchParams(window.location.search).get(param) != null)
return true
return false
}
console.log(queryParamExistUrl('id'))

Categories