SuiteScript2.0 Getting values from a saved search formula column - netsuite

I am trying to get the value from a formula field in a saved search. I am getting all the results and then looping through them as such.
for(key in itemReplenishResults){
log.debug("Single Data", JSON.stringify(itemReplenishResults[key]));
var thisNumber = Number(itemReplenishResults[key].getValue("formulanumeric_1"))
}
The log for the single data read as I would expect;
{
"recordType": "inventoryitem",
"id": "2131",
"values": {
"itemid": "ITEMCODE",
"displayname": "DISPLAYNAME",
"salesdescription": "SALESDESCRIPTION",
"type": [
{
"value": "InvtPart",
"text": "Inventory Item"
}
],
"location": [],
"locationquantityonhand": "",
"locationreorderpoint": "0",
"locationpreferredstocklevel": "1",
"formulatext": "Yes",
"formulanumeric": "1",
"locationquantityonorder": "",
"formulanumeric_1": "1",
"formulatext_1": "Yes"
}
}
But the value of thisNumber is returned as 0. I do not understand why this is not working?

The reason thisNumber is 0 is because the column formulanumeric_1 actually doesn't exist, so Number() is converting a null value to 0.
The problem
Formula columns are all named the same internally, which is why you can't directly get their values individually. For instance, if you have two Formula (Numeric) columns in your search, both internal column names will be "formulanumeric". Therefore, using getValue('formulanumeric') will get only the first formula value.
Logging a Result object will output the incorrect names as you have seen. If you log Result.columns you will see that the column names are actually the same.
Your choices
Directly get columns using indexes (if you care about ordering).
require(['N/search'], function(search) {
// A saved search containing multiple formula result columns
var s = search.load(1234);
s.run().each(function(result) {
log.debug(result.getValue(result.columns[5]));
log.debug(result.getValue(result.columns[1]));
log.debug(result.getValue(result.columns[3]));
});
});
Loop through each column (if you don't care about ordering).
require(['N/search'], function(search) {
// A saved search containing multiple formula result columns
var s = search.load(1234);
s.run().each(function(result) {
for (var i = 0; i < result.columns.length; i++) {
// Log each column's value in order
log.debug(result.getValue(result.columns[i]));
}
});
});
Manually define columns and reference them (the most versatile option). Column names must start with "formula[type]" and can be appended with anything else.
require(['N/search'], function(search) {
var s = search.create({
type: 'salesorder',
columns: [{
name: 'formulanumeric1',
formula: 'CASE WHEN 100 > 10 THEN 100 END'
}, {
name: 'formulanumeric2',
formula: 'CASE WHEN 30 > 20 THEN 30 END'
}]
});
s.run().each(function(result) {
log.debug(result.getValue('formulanumeric2')); // 30
log.debug(result.getValue('formulanumeric1')); // 100
});
});
NOTE: If you go with the first option, you'll have to be careful about reordering the columns in your initial search, as that will affect the indexing in the results.

When I'm working with formula fields, I always use the column index values. An example of one that I have is below. This matches up with the fifth column I created (starting at 0, of course). Hope that helps.
transactionSearch.run().each(function(r){
var var1=r.getValue(r.columns[5]);
var var2=r.getValue(r.columns[6]);
var var3=r.getValue(r.columns[7]);
var var4=r.getValue(r.columns[8]);
var var5=r.getValue(r.columns[9]);
return true;
});

Related

SUBSTITUTE based on a table of replacement strings

I have a list of business names and addresses in A, and shortened versions of just the business names with an added store # shown in B,
I would like to be able to paste a set of data into column D and have the file automatically find and substitute based on the info in the table, and output to column E.
The total number of potential substitutions is >200, so a nested SUBSTITUTE function would very quickly get too messy.
The sheet must handle multiples of the same entries in column D. i.e. The same business can appear multiple times in the raw data, and I want each entry to be subbed.
A4 and A5 represent the same location for my purposes, so the output needs to be the same between them.
A9 include a comma after "Sobeys", so the data formatting is not reliable enough to find the first comma and erase everything after.
This is currently being handled in Google Sheets, but if a more accessible solution exists in Excel I'd be willing to work there just for the substitutions. I've seen similar questions answered using QUERY or ARRAYFORMULA, but I'm out of my depth to try and adjust those answers to suit my needs here. Thank you!
To replace a big amount of data, try this (you have to enable the service Google Sheets API )
function replacements() {
const ar = [
{ text: "Example 1", newText: 'text1' },
{ text: "Example 2", newText: 'text2' },
{ text: "Example 3", newText: 'text3' },
];
const requests = ar.map(({ text, newText }) => ({ findReplace: { allSheets: true, find: text, replacement: newText, matchEntireCell: true, matchCase: true } }));
Sheets.Spreadsheets.batchUpdate({ requests }, SpreadsheetApp.getActive().getId());
}
You can construct the ar matrix based on your sheet in a separate spreadsheet (otherwise your table will also update). For instance
function replacements() {
var ar = []
var data = SpreadsheetApp.openById('id of the spreadsheet that contains the table').getSheets()[0].getDataRange().getValues()
data.forEach(function(r) {
var prov = {}
prov['text']=r[0]
prov['newText']=r[1]
ar.push(prov)
})
const requests = ar.map(({ text, newText }) => ({ findReplace: { allSheets: true, find: text, replacement: newText, matchEntireCell: true, matchCase: true } }));
Sheets.Spreadsheets.batchUpdate({ requests }, SpreadsheetApp.getActive().getId());
}

Multiple Select in Tabulator

Is it possible to have one select field depend on the previous one?
Users select one value from select_1 then accordingly the value in select_2 change. Maybe a custom formatter?
const newCol = {//create column group
title: oldRow.title,
field: oldRow.field,
columns: [
{
title: rowData.select1.title, field: rowData.select2.name, editor: 'select',
editorParams: {values: rowData.select1.values}
},
{
title: rowData.select2.title, field: rowData.select2.name, editor: 'select',
editorParams: function (cell) {
console.log(cell)
return {values: [1, 2, 3]}
}
},
],
}
From above I need select1 selected value.
Would this work Editors?:
"If you want to generate the options when the select editor is triggered, then you can pass a function into the editorParams, that must return the option list in one of the two formats outlined above"
{title:"Name", field:"name", editor:"select", editorParams:function(cell){
//create a options list of all values from another column in the table
var rows = table.getRows();
var values = {};
rows.forEach(function(row){
var data = row.getData();
values[data.fullname] = data.fullname;
});
return {values:values};
}
Instead of fetching the all the rows, just fetch the cell value of the previous select column and use that to build the choices for the current select. This sort of depends on the specifics of how the two columns relate to each other. More information on that would be helpful.

NodeJS Iterate through City in JSON, Return Cities and Users in each City

I have the below snippet from a JSON Object that has 3,500 records in it.
[
{
"use:firstName": "Bob",
"use:lastName": "Smith",
"use:categoryId": 36,
"use:company": "BobSmith",
"use:webExId": "Bob.Smith#email.com",
"use:address": {
"com:addressType": "PERSONAL",
"com:city": "US-TX",
"com:country": 1
}
},
{
"use:firstName": "Jane",
"use:lastName": "Doe",
"use:categoryId": 36,
"use:webExId": "Jane.Doe#email.com",
"use:address": {
"com:addressType": "PERSONAL",
"com:city": "US-CA",
"com:country": "1_1"
}
}
{
"use:firstName": "Sam",
"use:lastName": "Sneed",
"use:categoryId": 36,
"use:webExId": "Sam.Sneed#email.com",
"use:address": {
"com:addressType": "PERSONAL",
"com:city": "US-CA",
"com:country": "1_1"
}
}
]
I am using NodeJS and I have been stuck on figuring out the best way to:
1. Iterate through ['use:address']['com:city' to map out and identify all of the Cities. (In the example above, I have two: US-TX and US-CA in the three records provided)
2. Then identify how many records match each City (In the example above, I would have US-TX: 1 and US-CA: 2)
The only code I have is the easy part which is doing a forEach loop through the JSON data, defining userCity variable (to make it easier for me) and then logging to console the results (which is really unnecessary but I did it to confirm I was looping through JSON properly).
function test() {
const webexSiteUserListJson = fs.readFileSync('./src/db/webexSiteUserDetail.json');
const webexSiteUsers = JSON.parse(webexSiteUserListJson);
webexSiteUsers.forEach((userDetails) => {
let userCity = userDetails['use:address']['com:city'];
console.log(userCity);
})
};
I've been searching endlessly for help on the topic and probably not formulating my question properly. Any suggestions are appreciated on how to:
1. Iterate through ['use:address']['com:city' to map out and identify all of the Cities.
2. Then identify how many records match each City (In the example above, I would have US-TX: 1 and US-CA: 2)
Thank you!
You could reduce the webexSiteUsers array into an object that is keyed by city, where each value is the number of times the city occurs. Something like the below should work.
const counts = webexSiteUsers.reduce((countMemo, userDetails) => {
let userCity = userDetails['use:address']['com:city'];
if (countMemo[userCity]) {
countMemo[userCity] = countMemo[userCity] + 1;
} else {
countMemo[userCity] = 1;
}
return countMemo;
}, {});
counts will then be an object that looks like this.
{
"US-TX": 1,
"US-CA": 2
}

Get field value from Array based on another field data matching

Below is my sample JSON object. I want to get the 'title' value based
on the longitude value. I have multiple(20-30) longitudes to get the titles, so I don't want to loop through those many times:
{
items:[
{
longitude:-72.897668,
latitude:40.453576,
title:52 street
},
{
longitude:-71.897668,
latitude:41.453576,
title:5th Ave
}
]
}
Can anyone suggest me how to get value without using for-loops.
Did you try something linke array.filter()?
function filterByLongitude(element) {
var expected = -72.897668
return element.longitude === expected;
}
var items = [{
longitude:-72.897668,
latitude:40.453576,
title:'52 street'
}, {
longitude:-71.897668,
latitude:41.453576,
title: '5th Ave'
}];
var match = items.filter(filterByLongitude);
console.log(match[0].title); // 52 street

Arangodb removing subitems from document

How does one remove subitems from a document. So say I have a document called sales with each sale has a sale.item which contains {name,price,code}.
I want to remove each item which is not valid, by checking the code for blank or null.
Trying something like below fails with errors, am not sure if I need to use sub-query and how.
FOR sale in sales
FOR item in sale.items
FILTER item.code == ""
REMOVE item IN sale.items
Another attempt
FOR sale in sales
LET invalid = (
FOR item in sale.items
FILTER item.code == ""
RETURN item
)
REMOVE invalid IN sale.items LET removed = OLD RETURN removed
The following query will rebuild the items for each document in sales. It will only keep item whose code is not null and not the empty string:
FOR doc IN sales
LET newItems = (
FOR item IN doc.items
FILTER item.code != null && item.code != ''
RETURN item
)
UPDATE doc WITH { items: newItems } IN sales
Here is the test data I used:
db.sales.insert({
items: [
{ code: null, what: "delete-me" },
{ code: "", what: "delete-me-too" },
{ code: "123", what: "better-keep-me" },
{ code: true, what: "keep-me-too" }
]
});
db.sales.insert({
items: [
{ code: "", what: "i-will-vanish" },
{ code: null, what: "i-will-go-away" },
{ code: "abc", what: "not me!" }
]
});
db.sales.insert({
items: [
{ code: "444", what: "i-will-remain" },
{ code: null, what: "i-will-not" }
]
});
There's a better way to do this, without sub-queries. Instead, a function for removing an array element, will be used:
FOR doc IN sales
FOR item IN doc.items
FILTER item.code == ""
UPDATE doc WITH { items: REMOVE_VALUE( doc.items, item ) } IN sales
REMOVE_VALUE takes an array as the first argument, and an array item inside that array as the second argument, and returns an array that has all the items of the first argument, but without that specific item that was in the second argument.
Example:
REMOVE_VALUE([1, 2, 3], 3) = [1, 2]
Example with subdocuments being the values:
REMOVE_VALUE( [ {name: cake}, {name: pie, taste: delicious}, {name: cheese} ] , {name: cheese}) = [ {name: cake}, {name: pie, taste: delicious} ]
You cannot just use REMOVE_VALUE separately, the way you use the REMOVE command separately. You must use it as part of an UPDATE command not as part of a REMOVE command. Unfortunately, the way it works is to make a copy of the "items" list inside your one specific "doc" that you are currently dealing with, but the copy has the subdocument you don't like, removed from the "items" list. That new copy of the list replaces the old copy of the items list.
There is one more, most efficient way to remove subdocuments from a list - and that is by accessing the specific cell of the list with items[2] - and you have to use fancy array functions even fancier than the one I used here, to find out the specific cell in the list (whether it's [2] or [3] or [567]) and then to replace the contents of that cell with Null, using the UPDATE command, and then to set the options to KeepNull = false. That's the "most efficient" way to do it but it would be a monstrous looking complicated query ): I might write that query later and put it here but right now .. I would honestly suggest using the method I described above, unless you have a thousand subdocuments in each list.

Resources