Google Sheets Script Performance With Slow Custom Function - performance

Setup:
I have a Google sheet where I would like to run a custom function implemented using a script. This script is used to perform a relatively lengthy URL lookup and decode process (10 ms per call, dependent on bandwidth and ping). The custom function uses one column as input, and returns the result.
Problem:
When my Google sheet is opened, the column that uses this calculation is refreshed. This grinds the Google sheet to a halt for about 10 seconds, until each cell in the column is recalculated. This will only become worse as I add to my spreadsheet.
Question:
Can I change my function script, or change a setting in Google sheets so that the slow custom function is only calculated when the input cell is changed?
For anyone curious, here is a demo sheet with my problem

On my answer to In google sheets can I wrap a standard function in a custom function to control when it is run? I shared the idea of having a couple of buttons called "freeze" / "unfreeze" to control when the recalculation of "expensive formulas" is done.
On this case, you could "freeze" the range with your custom function before closing the spreadsheet so the next time that you open it will open faster, then when you need to update the frozen range you "unfreeze" it.
After posting the original version the OP asked for a simple version but as my original implementation was something quick and dirty with stuff in Spanish I shared there just the most important code lines. The core methods services are
A global variable to store the formula if it will always be the same
copyTo to overwrite the formula results range with the values a la copy-paste-values-only
clear to delete the formula results pasted previously
setFormula to add the formula back to the spreadsheet.
Then I realized that I could improved that published an unlisted Google Sheets add-on that use the PropertiesService to implement a "formula store" with functions to add/remove/list the formulas and a dynamic menu instead of buttons.
Something else to try is to use a time-driven trigger that runs, let say nightly just in case that you forgot to freeze the range for the custom function results.

Slightly better performance if there are less custom functions. You can rewrite your function to take in an array, so you'd only have one function instead of 100 running at once.
function mySlowFunction(x) {
//Utilities.sleep(x*100); //100 ms
if (x.map) {
return x.map(function(y) {return mySlowFunction(y) });
} else {
return x * 100;
}
}

Related

Power Automate create folder from excel cell

I'm trying to create a folder as part of a flow, based upon an excel cell value.
The flow works if I use a cell value from the excel sheet that is a straight value such as "Folder 1", but just comes up blank when I use a cell that is a formula such as "=B2 & " RFE " & ROW(2:2)".
Is there a way to get past this? Am I right in thinking that it's not working because I'm referencing a formula and not a value?
I can't speak to your flow specifically and the issue you're seeing with the way you're retrieving that value (you haven't shown it) but another way to pull data from Excel and be a lot more specific about it is to use Office Scripts.
If you've never used them before, this can help you get started.
https://support.microsoft.com/en-us/office/introduction-to-office-scripts-in-excel-9fbe283d-adb8-4f13-a75b-a81c6baf163a#:~:text=Getting%20started,steps%20you%20want%20to%20automate.
In relation to a script that can help you, if you create a new script called Get Cell Value and paste this code in ...
function main(workbook: ExcelScript.Workbook, worksheetName: string, cellAddress: string)
{
return workbook.getWorksheet(worksheetName).getRange(cellAddress).getText();
}
... you can then call it from PowerAutomate and it will give you the right answer.
You can see in my example, the first cell is a formula. From PowerAutomate using the Run script action, it works as expected.
You can then use the resulting value to create your folder.

Google sheet XPath scraping: copy currency exchange rate

From this URL https://www.xe.com/currencyconverter/convert/?Amount=1&From=MYR&To=INR I want to copy the data into my google sheets.
in cell A1 I have https://www.xe.com/currencyconverter/convert/?Amount=1&From=MYR&To=INR
in cell A2 I have =IMPORTXML(A1,"//span[#class='converterresult-toAmount']")
I get output N\A
Can someone advise me how?
Alternatively, you can use the GOOGLEFINANCE formula to fetch the FX rates from Google Finance directly:
=index(GOOGLEFINANCE("CURRENCY:MYRINR","price",today(),1,"DAILY"),2,2)
This function will return the daily FX rate for MYR-INR for today.
See GOOGLEFINANCE documentation for more details about the variations you can use to get more / different data.
I wrapped the Google Finance formula into an INDEX function to only get the rate (so you can use that in a multiplication to convert random amounts), as the GOOGLEFINANCE formula returns a table with dates and history by default.
unfortunately, that won't be possible because the site is controlled by JavaScript and Google Sheets can't understand/import JS. you can test this simply by disabling JS for a given link and you will see a blank page:

Resources for Building Dynamic Lift Shopping Cart?

Here's what I'd like to do with Lift: I want to build a dynamic shopping cart, with lines able to be added and removed via AJAX calls. The total needs to be wired to the specific lines. Each line would include a number, the length of time for a lease, and a calculated price based on that, so I would have to add wired cells on each addable/removable line as well. So it would look something like this:
Number Length of Lease Price Remove?
(AJAX Textbox) (AJAX Dropdown Select) (Plain Updateable Text) (Ajax Checkbox)
(Another Row)...
+ Add
Total: ______
The problem I'm running into is that I can find resources to build a static page that displays all of this via Wiring. Using the Lift Demo site, I can pull up code that will let me add new lines, but it doesn't seem to me to be conducive to removing lines (this in general is one of my frustrations with Lift at the moment: a "little extra detail" to change from a tutorial ends up requiring me to completely change tacks and spend hours more at work and research, and I want to figure out how I'm probably approaching these problems wrongly!). Alternatively, I can use CSS selectors to dynamically create content, but I don't know how to effectively wire these together.
In addition, all of my attempts end up creating 2-3 times the amount of code I would have written to simply do some JQuery updates on the page, so I suspect that I'm doing something wrong and overcomplicating everything.
What resources would people recommend to set me on the right path?
These are your best resources for learning Lift:
Simply Lift
Lift Cookbook
Lift in Action
For any specific questions, I highly recommend you join us at the Lift Community Google Group. It is the official support channel for Lift. Although a few of us occasionally help out here at Stackoverflow, the best Lift help can be found there.

Can a google apps scripts be paused to allow a sheet to finish sorting?

I have a Google sheet that I am exporting as a PDF using a script. Since I would like to run this weekly and additional entries may be made before exporting to PDF, I would like to run a sort function to ensure that the export PDF is in chronological order. When I added a sort and run the script, I see the sheet update from the sort and then receive the PDF by email, but the PDF is from before the sort.
Is there anyway to delay the rest of the script after I run the sort? Does anyone have another idea to solve this problem?
function ZIP_PDF_EMAIL() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Project Tracking');
//call sort function
sort(s);
//remainder of pdf export code
You can use the spreadsheet method spreadsheetApp.flush() that is documented here and updates the whole sheet so that all pending changes are made right away

Solution for Magento mass actions and large number of records problem?

Currently Magento has a problem with the way it handles mass actions. It returns a bit of JS that contains EVERY db id for the current collection and filter, regardless of pagination. This is to support the 'Select All' vs. 'Select All Visible' option in the grid header. This isn't such a problem when you have a smaller number of records, but if you have 850k records (orders in this case) it becomes a serious problem.
My question is, does anyone have an elegant solution to this problem?
I can think of several solutions, each with its own drawbacks, but I'm hoping someone has solved this in a simple manner that works as an add-on module. Paid or Open-Source solutions are both welcome suggestions.
Clarification:
I'm looking for an elegant/drop-in solution to the problem of 850k+ records using the grid widget in Magento. The stock Magento code makes the bone headed decision to return the id for every record that is matched by the current filter, even if they are not being displayed. This is not about offline processing of records, it's about using the grid widget for daily admin tasks.
One possible solution would be to store the results of the filtered search in a temp table and return a reference to the search result. Then you could change it from using the actual ids on a 'Select All' to using a specific callback for the action using the reference. This would preserve the current behavior.
So, to ask again, does anyone have a good solution to this already created?
I'm running heavy operations from within a shell script. I have a generic iterator (in my case products, but can be done with everything else), and I only implement a class that does the action on the product. My product_iterator shell script takes care of looping over the products, while processing only x products at once (to avoid memory leaks).
Well, the least invasive solution to the problem is to turn off the 'Select All' option for grids with large numbers of records. This is easily accomplished by extending the grid class and adding the following code:
protected function _prepareMassaction()
{
$this->getMassactionBlock()->setUseSelectAll(false);
return parent::_prepareMassaction();
}
I think that fbmc has the right general approach. Clearly, even if you did find a way to send back all 850k records, the framework would have a heart attack attempting to deal with them all. Run the logic in a shell script if this is what you need. For some jobs, you may even need to run them in batches or move down to actual SQL logic.
Unfortunately, some parts of the framework were not made to handle this kind of scale. You've found one of them.
Hope that helps!
Thanks,
Joe
Recently i have written an article about 'Adding new mass action to admin grid in Magento',
Hopefully you will like it:
http://www.blog.magepsycho.com/adding-new-mass-action-to-admin-grid-in-magento/
It describes the two way for adding Mass Action
1> Extending Grid Layouts _prepareMassaction() method
2> Using event: core_block_abstract_prepare_layout_before (more upgrade proof way)
Thanks
Regards

Resources