combining replacer and fields in json.stringify - javascript

How would I use white-list of fields and a replace function at the same time when using json.stringify?
How to stringify objects through JSON's replacer function?
explains how to use a field list.
Hide null values in output from JSON.stringify()
Has an answer for filtering null values: https://stackoverflow.com/a/41116529/1497139
Based on that code snippet i am trying:
var fieldWhiteList=['','x1','x2','children'];
let x = {
'x1':0,
'x2':null,
'x3':"xyz",
'x4': null,
children: [
{ 'x1': 2, 'x3': 5},
{ 'x1': 3, 'x3': 6}
]
}
function replacer(key,value) {
if (value!==null) {
if (fieldWhiteList.includes(key))
return value;
}
}
console.log(JSON.stringify(x, replacer,2));
And the result is:
{
"x1": 0,
"children": [
null,
null
]
}
Which is not what I expected. I would have expected the x1 values for the children to show up and not null values.
How could i achieve the expected result?
see also jsfiddle

By adding some debug output to the fiddle
function replacer(key,value) {
if (value!==null) {
if (fieldWhiteList.includes(key))
return value;
}
console.log('ignoring '+key+'('+typeof (key)+')');
}
I got the output:
ignoring x2(string)
ignoring x3(string)
ignoring x4(string)
ignoring 0(string)
ignoring 1(string)
ignoring 2(string)
{
"x1": 0,
"children": [
null,
null,
null
]
}
which showed that potentially the keys can be array indices. In this case they are all numbers from 0 to n in string format so:
adding a regular expression to match numbers fixed the issue
function replacer(key,value) {
if (value!==null) {
if (fieldWhiteList.includes(key))
return value;
if (key.match('[0-9]+'))
return value;
}
console.log('ignoring '+key+'('+typeof (key)+')');
}
with the expected output:
ignoring x2(string)
ignoring x4(string)
{
"x1": 0,
"x3": "xyz",
"children": [
{
"x1": 2,
"x3": 5
},
{
"x1": 3,
"x3": 6
},
{
"x1": 4,
"x3": 7
}
]
}

Related

Javascript parse array of object strings into object of objects?

I am working with a 3rd party app that requires a specific structure of data for filtering a result set. I am struggling with figuring out how to parse this out as the end result isn't a conventional array of objects.
There is a function that takes in a list of IDs from an array and turns them into object strings:
Function:
// Input for articles is an array of IDs
// articles = ['kA10W000001UK2KSAW', 'kA1d0000000DB1CCAW', 'kA1d0000000DAsOCAW']
function createExclusion(articles){
let results = [];
articles.forEach(element => {
results.push(`"EqualsTo": {"Key": "sf_KnowledgeArticleId","Value": {"StringValue":"${element}"}}`)
})
return result;
}
Input Data:
let data = [
'"EqualsTo":{"Key":"sf_KnowledgeArticleId","Value":{"StringValue":"kA10W000001UK2KSAW"}},',
'"EqualsTo":{"Key":"sf_KnowledgeArticleId","Value":{"StringValue":"kA1d0000000DB1CCAW"}},',
'"EqualsTo":{"Key":"sf_KnowledgeArticleId","Value":{"StringValue":"kA1d0000000DAsOCAW"}}'
]
Desired End Result:
{
IndexId: 1,
PageSize: 2,
PageNumber: 3,
RequestedDocumentAttributes: ["_source_uri", "sf_ArticleNumber", "sf_KnowledgeArticleId"],
AttributeFilter: {
"NotFilter": {
"EqualsTo": {
"Key": "sf_KnowledgeArticleId",
"Value": {
"StringValue": "kA10W000001UK2KSAW"
}
},
"EqualsTo": {
"Key": "sf_KnowledgeArticleId",
"Value": {
"StringValue": "kA1d0000000DB1CCAW"
}
},
"EqualsTo": {
"Key": "sf_KnowledgeArticleId",
"Value": {
"StringValue": "kA1d0000000DAsOCAW"
}
},
},
SortingConfiguration: {
"DocumentAttributeKey": "_document_title",
"SortOrder": "ASC"
}
};
}
I am trying to re-create the AttributeFilter data in the end result by taking the array of strings and parsing it into the correct form.
Example:
I was trying to get it to work with JSON.parse(), but the data isn't in the correct format for that.
Between either adjusting the createExclusion function or easily parsing it in its existing form, how can I go about turning the list of object strings into just objects as seen in the desired end result?
function parse(data) {
return {
IndexId: 1,
PageSize: 2,
PageNumber: 3,
RequestedDocumentAttributes: ["_source_uri", "sf_ArticleNumber", "sf_KnowledgeArticleId"],
AttributeFilter: {
"NotFilter": ? // Parse data here
},
SortingConfiguration: {
"DocumentAttributeKey": "_document_title",
"SortOrder": "ASC"
}
};
}
First, you cannot have an object with duplicated keys in JSON:
{
"NotFilter": {
"EqualsTo": {
"Key": "sf_KnowledgeArticleId",
"Value": {
"StringValue": "kA10W000001UK2KSAW"
}
},
"EqualsTo": {
"Key": "sf_KnowledgeArticleId",
"Value": {
"StringValue": "kA1d0000000DB1CCAW"
}
},
"EqualsTo": {
"Key": "sf_KnowledgeArticleId",
"Value": {
"StringValue": "kA1d0000000DAsOCAW"
}
}
}
}
Your NotFilter value should be an array of objects.
Parsing JSON
Your JSON should be valid, prior to calling JSON.parse. Make sure you remove any trailing commas and wrap each line in curly-braces.
let data = [
'"EqualsTo":{"Key":"sf_KnowledgeArticleId","Value":{"StringValue":"kA10W000001UK2KSAW"}},',
'"EqualsTo":{"Key":"sf_KnowledgeArticleId","Value":{"StringValue":"kA1d0000000DB1CCAW"}},',
'"EqualsTo":{"Key":"sf_KnowledgeArticleId","Value":{"StringValue":"kA1d0000000DAsOCAW"}}'
]
const parsed = data.map(item => JSON.parse(`{${item.replace(/,$/, '')}}`));
console.log(parsed);
.as-console-wrapper { top: 0; max-height: 100% !important; }

Is there any way to display 0 when an array is [""]?

I have an object that I'm iterating over using Object.keys(myData).map
const data = Object.keys(myData);
const output = data.map(key => (
{myData[key].bad.length} //correctly shows 2 for "bad" on "Bravo", but will show 1 for "bad" on "Charlie" when the array is[""]
));
Data
{
"Alpha": {
"bad": ["0001-00"],
"good": ["0002-00", "0003-00", "0004-00"],
"percent": 10,
"optionOne": true,
"optionTwo": false
},
"Bravo": {
"bad": ["0002-11", "0003-01"],
"good": ["0002-14", "0005-06"],
"percent": 75,
"optionOne": true,
"optionTwo": true
},
"Charlie": {
"bad": [""],
"good": ["0131-00", "0007-13", "0001-92"],
"percent": 25,
"optionOne": true,
"optionTwo": false
}
}
I have this to display how many items are in the array, but when they array is [""] it will display 1. Any suggestion on how I will be able to display 0 when there array is [""]?
I have all of my code working here: https://repl.it/repls/DapperHungryFraction
You could filter the array before taking the length.
This filters out empty strings:
myData[key].bad.filter(x=> x !== "").length;

Array Sorting in an object in javascript

I have to sort the arrays of the "Key" in ascending order and here's what I am doing .
Surprsingly the first array is getting sorted in descending order and the next two in ascending order . Whats the possible reason for this?
var MainObject4 = [{ "mainarray": [{ "Key": [9,768,78] },
{ "Key": [9,4,1] },{ "Key": [49,89,54] }]
}];
var first = MainObject4[0];
Object.keys(MainObject4[0]).forEach(function (k) {
first[k].forEach(function (j) {
Object.keys(j).forEach(function (g) {
j[g].sort();
},this);
},this);
},this);
alert(JSON.stringify(MainObject4, 0, 4));
Expected output:
[9,78,768]
[1,4,9]
[49,54,89]
Output I am getting now:
[768,78,9]
[1,4,9]
[49,54,89]
See the doc of Array.sort()
The default sort order is according to string Unicode code points.
If you want to compare numbers, you need to provide the comparison function, as said in the doc :
To compare numbers instead of strings, the compare function can simply subtract b from a.
You need to add a function to compare sort parameters:
var MainObject4 = [{
"mainarray": [{
"Key": [9, 768, 78]
}, {
"Key": [9, 4, 1]
}, {
"Key": [49, 89, 54]
}]
}];
var first = MainObject4[0];
Object.keys(MainObject4[0]).forEach(function(k) {
first[k].forEach(function(j) {
Object.keys(j).forEach(function(g) {
j[g].sort(function(a, b) {
return a - b;
});
}, this);
}, this);
}, this);
alert(JSON.stringify(MainObject4, 0, 4));
var MainObject4 = [{ "mainarray": [
{ "Key": [9,768,78] },
{ "Key": [9,4,1] },
{ "Key": [49,89,54] }
]
}];
MainObject4[0].mainarray.forEach(function (j) {
Object.keys(j).forEach(function (g) {
j[g].sort(function (a, b) {
return a - b;
});
},this);
},this);
alert(JSON.stringify(MainObject4, 0, 4));
It's happening because of JavaScript's sort method takes by default unicode to compare the elements. For sorting numbers, you have to explicitly write a call back function to compare elements. For ex
var input = [1,20,2,12];
console.log(input.sort());// prints 1,12,2,20
console.log(input.sort(function(a,b){
return a-b;
}));// prints 1,2,12,20
So, You just need to add the compare function to your sort. That's all

Sort with custom function giving reversed results

I have the following array (here shown as JSON):
[{
"value": -1,
"absolute": false,
"callTime": 0
}, {
"value": 23,
"absolute": true,
"callTime": 1365179295887
}, {
"value": 1,
"absolute": false,
"callTime": 0
}, {
"value": 1,
"absolute": true,
"callTime": 0
}]
I need to sort this array by putting the objects with the highest values of the callTime property at the top of the array.
I use the following code (based on the explanation of the subject offered by MDN):
var handlers = JSON.parse("[...]");
handlers.sort(function(firstHandler, secondHandler) {
if (firstHandler.callTime < secondHandler.callTime) {
return -1; // sort firstHandler to a lower index than secondHandler.
} else {
return 1; // sort secondHandler to a lower index than firstHandler.
}
return 0;
});
console.log(JSON.stringify(handlers));
After running the function, I get the following output:
[{
"value": 1,
"absolute": true,
"callTime": 0
}, {
"value": 1,
"absolute": false,
"callTime": 0
}, {
"value": -1,
"absolute": false,
"callTime": 0
}, {
"value": 94,
"absolute": true,
"callTime": 1365179553381
}]
Which seems to be the inverse of what I'm expecting (notice how the only object with callTime different than zero is at the bottom).
I think there I might be missing something big here, or maybe I'm just misled, but also changing the body of the function to:
return firstHandler.callTime - secondHandler.callTime
should give the correct results, yet it doesn't seem to.
What could I be doing wrong?
Your sort function is incorrect. The logic is reversed, because your sort function is indicating that elements with smaller values of callTime come first, whereas you want larger values to be at the top of the array. Also, you always return -1 or 1, and never 0. It should return 0 when the elements are tied.
Rewrite it as follows:
handlers.sort(function(firstHandler, secondHandler) {
if (firstHandler.callTime > secondHandler.callTime) {
return -1; // sort firstHandler to a LOWER index than secondHandler.
} else if (firstHandler.callTime < secondHandler.callTime) {
return 1; // sort secondHandler to a LOWER index than firstHandler.
}
return 0; // sort firstHandler and secondHandler as equal
});

json - How to properly create json array

Im new to JSON and I have to deal with a complex one.
Please see image below:
It has an error:
I don't know how to properly separate the 2 json arrays. I even tried to use : instead of , on line 18 but I still get errors. BTW, I use http://jsonlint.com/ to validate.
On line 2 you gave a key, but failed to do so on line 19. You have to keep the structure.
Remove the key on line 2, they shouldn't be used for arrays in that way.
Edit: In addition, you are trying to put arrays right in objects, switch the opening and ending object marks ({}) with ([]) for arrays on your first and last line.
[
[
{...},
{...},
...
{...}
],
[
{...},
{...},
...
{...}
],
...
[
{...},
{...},
...
{...}
]
]
I believe the correct way to build this JSON should be:
{
"glEntries": [
{
"generalLedgerId":1,
"accountId": 34,
"amount" : 32334.23,
"descripction": "desc1",
"debit" : "Yes"
},
{
"generalLedgerId":2,
"accountId": 35,
"amount" : 323.23,
"descripction": "desc",
"debit" : "Yes"
},
...
]
}
There are many ways to construct JSON data, but it depends on your data and the way you want to present it. Here are a couple examples - hope it helps:
{
"glEntries": [
{
"object1-prop1": "one"
},
{
"object2-prop1": 1,
"object2-prop2": "two"
},
{
"object3-prop1": [
"a",
"r",
"r",
"a",
"y"
],
"object3-prop1.1": "string"
}
],
"otherEntries": [
{
"objectx": "x"
},
{
"objecty": "y"
},
{
"objectz": [
1,
2,
3,
4
]
}
],
"oneEntry": "json"
}
Other Example:
[
{
"obj1-prop": 222
},
{
"obj2-prop": "object2"
},
{
"obj3-prop": "Object3"
},
[
"a",
"r",
"r",
"a",
"y",
777,
888
],
"string",
178,
{
"objectProp": "testing123"
}
]
You have more {} than needed and will make parsing your JSON more difficult:
Structure will work a lot better like this:
{"glentries":[
{ "property1":"value", "property2" : "value",..... "lastProperty": "value"},
{ "property1":"value", "property2" : "value",..... "lastProperty": "value"},
{ "property1":"value", "property2" : "value",..... "lastProperty": "value"}
]
}
Now glentries is an array of objects that have multiple properties to them.
alert( glentries[0].property2 )
The parent structure is an Object, so it is expecting a string Key for the second array. It it's supposed to be an array of arrays, you should be using an array and not an Object.

Categories