How to make array in object while parsing? - javascript

I am parsing the JSON object. I want to set value which is stored in session against id. I have this JSON:
[
{
"id": "a",
"text": "a",
"icon": true,
"li_attr": {
"id": "a"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "b",
"text": "b\n ",
"icon": true,
"li_attr": {
"id": "b"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
{
"id": "b-a-1",
"text": "b-a",
"icon": true,
"li_attr": {
"id": "b-a-1"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "b-b-2",
"text": "b-b\n ",
"icon": true,
"li_attr": {
"id": "b-b-2"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
{
"id": "b-b-a",
"text": "b-b-a",
"icon": true,
"li_attr": {
"id": "b-b-a"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "b-b-b",
"text": "b-b-b",
"icon": true,
"li_attr": {
"id": "b-b-b"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
}
]
}
]
},
{
"id": "c-1",
"text": "c\n ",
"icon": true,
"li_attr": {
"id": "c-1"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
{
"id": "not-c-a-1",
"text": "c-a",
"icon": true,
"li_attr": {
"id": "not-c-a-1"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
},
{
"id": "not-c-b-2",
"text": "b-b",
"icon": true,
"li_attr": {
"id": "not-c-b-2"
},
"a_attr": {
"href": "#"
},
"state": {
"loaded": true,
"opened": false,
"selected": false,
"disabled": false
},
"data": {
},
"children": [
]
}
]
}
]
I want to make same type array having object. Inside the object there might be possibility of nested objects. I just want to set value against it id.
Can we get the information of children? If there are children, I need to set value. Here is my fiddle:
http://jsfiddle.net/fuu94/91/
$('#json').click(function(){
var json_list=$('#tree').jstree(true).get_json(); console.log(json_list.length);
for(var i=0;i<json_list.length;i++){
var obj={};
alert(json_list[i].id)
obj=sessionStorage.getItem(json_list[i].id);
arr[i]=obj;
}
console.log(arr)
})
});
Expected output is:
[
{
"a": "value_a",
"arr": [
]
},
{
"b": "value_b",
"arr": [
{
"b-a-1": "value_b-a-1",
"arr": [
]
},
{
"b-b-1": "value_b-b-2",
"arr": [
{
"b-b-a": "value_b-b-a",
"arr": [
]
},
{
"b-b-b": "value_b-b-b",
"arr": [
]
}
]
}
]
},
{
"c-1": "value_c-1",
"arr": [
{
"not-c-a-1": "value_not-c-a-1",
"arr": [
]
},
{
"not-c-b-2": "value_not-c-b-2",
"arr": [
]
}
]
}
]

You could use a reviver function that you pass to JSON.parse.
JSFIDDLE
var json = JSON.stringify([{ id: 'root', children: [ { id: 'nested' } ]}]);
var p = JSON.parse(json, function (k, v) {
if (!k) return v;
if (k === 'id' || k === 'children') return v;
if (+k == k && typeof v === 'object' && v != null && 'id' in v) {
v[v.id] = 'value_' + v.id;
delete v.id;
if (v.children) v.arr = v.children;
delete v.children;
return v;
}
});
JSON.stringify(p); //[{"root":"value_root","arr":[{"nested":"value_nested"}]}]
EDIT: I tried to make the code more robust by using a different approach, but it did not work as expected because the children key did not always came before we started to iterate over the array. Have a look at the edit history, perhaps I overlooked something.

Assuming that "b-b-1": "value_b-b-2" in the expected output is a type and really should be "b-b-2": "value_b-b-2" it should be very easy to map the original array to the expected output.
Use the map method on arrays (or, if you need to support older browsers, use the map implementation of some library you are using (e.g. jQuery or Underscore).
For each of the items in your array, you need to create an item which has two properties. The first property should be named according to the value of the id property of the input object and the value of the property seems like it should be the literal value_ followed by the value of the id property from the input object.
Furthermore, each item should also have an arr property, which is the result of applying our item mapping function to the items in the children array.
So the code could look something like
function mapItem(inputItem){
var item = {};
item[inputItem.id] = "value_" + inputItem.id;
item.arr = inputItem.children.map(mapItem);
return item;
};
var results = originalArray.map(mapItem);
I have the above mapping function running against your sample data at http://jsfiddle.net/tJ7Kq/

Related

Related content from JSON & API

i have a json returned from an api that shows latest discussions from a forum..
the url that display the json output is like:
https://example.com/api/discussions?isApproved=true&exists=true&sort=-lastPostedAt
and this is the json output:
"links": {
"first": "http://localhost/flarum/public/api/discussions?isApproved=true\u0026exists=true\u0026sort=-lastPostedAt",
"next": "http://localhost/flarum/public/api/discussions?isApproved=true\u0026exists=true\u0026sort=-lastPostedAt\u0026page%5Boffset%5D=20"
},
"data": [
{
"type": "discussions",
"id": "46",
"attributes": {
"title": "footer",
"slug": "46-footer",
"commentCount": 1,
"participantCount": 1,
"createdAt": "2021-09-20T07:14:18+00:00",
"lastPostedAt": "2021-09-20T07:14:18+00:00",
"lastPostNumber": 1,
"canReply": true,
"canRename": true,
"canDelete": true,
"canHide": true,
"lastReadAt": "2021-09-20T07:14:20+00:00",
"lastReadPostNumber": 1,
"isApproved": true,
"canTag": true,
"subscription": null,
"isLocked": false,
"canLock": true
},
"relationships": { "user": { "data": { "type": "users", "id": "1" } }, "lastPostedUser": { "data": { "type": "users", "id": "1" } }, "tags": { "data": [{ "type": "tags", "id": "2" }] } }
},
{
"type": "discussions",
"id": "45",
"attributes": {
"title": "fhgfhfg",
"slug": "45-fhgfhfg",
"commentCount": 2,
"participantCount": 1,
"createdAt": "2021-09-19T16:07:37+00:00",
"lastPostedAt": "2021-09-19T23:04:00+00:00",
"lastPostNumber": 2,
"canReply": true,
"canRename": true,
"canDelete": true,
"canHide": true,
"lastReadAt": "2021-09-19T23:04:02+00:00",
"lastReadPostNumber": 2,
"isApproved": true,
"canTag": true,
"subscription": null,
"isLocked": false,
"canLock": true
},
"relationships": { "user": { "data": { "type": "users", "id": "1" } }, "lastPostedUser": { "data": { "type": "users", "id": "1" } }, "tags": { "data": [{ "type": "tags", "id": "2" }] } }
},
{
"type": "discussions",
"id": "39",
"attributes": {
"title": "Discussion",
"slug": "39-discussion",
"commentCount": 21,
"participantCount": 1,
"createdAt": "2021-05-22T11:06:43+00:00",
"lastPostedAt": "2021-09-04T12:49:32+00:00",
"lastPostNumber": 28,
"canReply": true,
"canRename": true,
"canDelete": true,
"canHide": true,
"lastReadAt": "2021-09-04T12:49:34+00:00",
"lastReadPostNumber": 28,
"isApproved": true,
"canTag": true,
"subscription": null,
"isLocked": false,
"canLock": true
},
"relationships": { "user": { "data": { "type": "users", "id": "1" } }, "lastPostedUser": { "data": { "type": "users", "id": "1" } }, "tags": { "data": [{ "type": "tags", "id": "1" }] } }
}
what i want to do is to have something like "related content" based on a discussion title. For example if i have this title "lets talk about cars", the json must shows all the discussions related to this title.
is this possible?
You can take the data from json and just filter the content inside
const filteredResults = yourJsonResponse.data.filter(item => item.attributes.title === 'lets talk about cars')
This won't be a good idea. as you're getting paginated list with limit(like per page 20/30). if you're using js you can use js filter for getting related content. But as i said. that filer will be done based on your current page data, not all data. it's better to use another api end for related content from large data..

Filtering data on the basis of condition

I am working on an angular application. My data is as follows.
const data = [{
"checked": true,
"children": [{
"checked": true,
"data": {
"name": "myName"
},
"parent": {
"checked":true,
"data": {
"name": "myName2"
},
"parent": {
"checked":true,
"data": {
"name": "myName3"
}
}
}
}, {
"checked": true,
"data": {
"name": "myNamePart2"
},
"parent": {
"data": {
"name": "myName2"
},
"parent": {
"data": {
"name": "myName3"
}
}
}
}
]
}, {
"checked": false,
"children": [{
"checked": true,
"data": {
"name": "myName4"
},
"parent": {
"data": {
"name": "myName5"
},
"parent": {
"data": {
"name": "myName6"
}
}
}
}
]
}, {
"checked": true,
"children": [{
"checked": true,
"data": {
"name": "myName7"
},
"parent": {
"data": {
"name": "myName8"
},
"parent": {
"data": {
"name": "myName9"
}
}
}
}
]
},
{
"checked": true,
"data": {
"name": "myName10"
},
"parent": {
"data": {
"name": "myName11"
},
"parent": {
"data": {
"name": "myName12"
}
}
}
},
{
"checked": false,
"data": {
"name": "myName13"
},
"parent": {
"data": {
"name": "myName14"
},
"parent": {
"data": {
"name": "myName15"
}
}
}
}
];
My expected output is :
In this array, if for any index if "checked" is true, then I want to check the "checked" flag for each child. If for any children, if the "checked" flag is true, then I want to have data from parent name to children name separated by "/" in an array. For the above data, my final array will have.
[
"myName3/myName2/myName",
"myName3/myName2/myNamePart2",
"myName9/myName8/myName7",
"myName12/myName11/myName10"
]
My code is as follows which gives me correct output
const compute = data =>
data
.flatMap(x => x.checked || x.children)
.concat(data)
.filter(x => x && x.checked && x.data)
.map(x => createPath(x))
.map(x => x.join("/"));
const createPath = (node, currentPath = []) =>
node.parent
? createPath(node.parent, [node.data.name, ...currentPath])
: [node.data.name, ...currentPath];
In this solution, I just want to add one more condition which is as follows:
If the "checked" flag is true from child to parent, then in my result array I want to have the only parent.
For example, in my data above I have a node with children and parent as follows
"checked": true,
"children": [{
"checked": true,
"data": {
"name": "myName"
},
"parent": {
"checked":true,
"data": {
"name": "myName2"
},
"parent": {
"checked":true,
"data": {
"name": "myName3"
}
}
}
}
In this, all the "checked" flags from parent-child to parent or we can say from parent to child are true. Then in this case I want to have my output for this in the result array as follows:
[
"myName3",
"myName3/myName2/myNamePart2",
"myName9/myName8/myName7",
"myName12/myName11/myName10"
]
Only having "myName3" as all checked flag is true from child to parent. In case if "checked" true is not for child or parent then my code should work as it is working now. How I can do this?

Merge source JSON string to target with similar keys but different structure in javascript

I have two JSON strings as shown below:
source = [
{
"name": "test1",
"values": ["User Support"],
"enabled": false
},
{
"name": "test2",
"values": ["M"],
"enabled": true
},
{
"name": "test3",
"values": ["CA"],
"enabled": false
}
]
target = [{
"name": "test1",
"values": [{
"value": "User Support",
"selected": false
},
{
"value": "Engineering",
"selected": false
},
{
"value": "Implementation",
"selected": false
}
],
"enabled": false
},
{
"name": "test2",
"values": [{
"value": "M",
"selected": false
},
{
"value": "F",
"selected": false
}
],
"notEnabled": false
},
{
"name": "test3",
"values": [{
"value": "CA",
"selected": false
},
{
"value": "EN",
"selected": false
}
],
"enabled": false
}
]
I want to merge both these JSON strings into target and the resultant should look like:
target = [{
"name": "test1",
"values": [{
"value": "User Support",
"selected": true
},
{
"value": "Engineering",
"selected": false
},
{
"value": "Implementation",
"selected": false
}
],
"enabled": false
},
{
"name": "test2",
"values": [{
"value": "M",
"selected": true
},
{
"value": "F",
"selected": false
}
],
"enabled": true
},
{
"name": "test3",
"values": [{
"value": "CA",
"selected": true
},
{
"value": "EN",
"selected": false
}
],
"enabled": false
}
]
So, what I am trying to do is search in target string for name as test1, test2.... and then set the selected field as true if the value is found in source JSON string. Same is the case for enabled field.
First thing that comes to my mind is to use nested for each loops and check for the keys.
Is there any other better way to do this in Javascript?
Note that there could be other keys present inside target string, but we don't bother about them unless they are present in source string.
If you don't mind lodash:
const _ = require('lodash');
const sourceJSON = '[{"name":"test1","values":["User Support"],"enabled":false},{"name":"test2","values":["M"],"enabled":true},{"name":"test3","values":["CA"],"enabled":false}]';
const targetJSON = '[{"name":"test1","values":[{"value":"User Support","selected":false}, {"value":"Engineering","selected":false},{"value":"Implementation","selected":false}],"enabled":false},{"name":"test2","values":[{"value":"M","selected":false}, {"value":"F","selected":false} ],"notEnabled":false},{ "name":"test3","values": [{"value":"CA","selected":false},{"value":"EN","selected":false}],"enabled":false}]';
const source = JSON.parse(sourceJSON);
const target = JSON.parse(targetJSON);
const sourceNormalized = source.map((obj) => (
{ ...obj, values: [{value: obj.values[0], selected: true}] }
));
const merged = _.defaultsDeep(sourceNormalized, target);
console.dir(merged, {depth: null});
// [ { name: 'test1',
// values: [
// { value: 'User Support', selected: true },
// { value: 'Engineering', selected: false },
// { value: 'Implementation', selected: false }
// ],
// enabled: false
// },
// { name: 'test2',
// values: [
// { value: 'M', selected: true },
// { value: 'F', selected: false }
// ],
// enabled: true,
// notEnabled: false
// },
// { name: 'test3',
// values: [
// { value: 'CA', selected: true },
// { value: 'EN', selected: false }
// ],
// enabled: false} ]
result = JSON.stringify(merged);
The previous answer using lodash is a very good approach. In case you are in a situation such as myself (stuck working on a code-base where packages, including lodash, are difficult to get approved-for-use), here is an approach using Vanilla-javascript (+ JSON.stringify):
const delta = [{
"name": "test1",
"values": ["User Support"],
"enabled": false
},
{
"name": "test2",
"values": ["M"],
"enabled": true
},
{
"name": "test3",
"values": ["CA"],
"enabled": false
}
];
const orig = [{
"name": "test1",
"values": [{
"value": "User Support",
"selected": false
},
{
"value": "Engineering",
"selected": false
},
{
"value": "Implementation",
"selected": false
}
],
"enabled": false
},
{
"name": "test2",
"values": [{
"value": "M",
"selected": false
},
{
"value": "F",
"selected": false
}
],
"notEnabled": false
},
{
"name": "test3",
"values": [{
"value": "CA",
"selected": false
},
{
"value": "EN",
"selected": false
}
],
"enabled": false
}
];
const getTargetJSON = (delta, orig, debug = true) => { // method signature
const deltaMapper = delta.reduce((f, i) => ({
...f,
[i.name]: {
values: [...i.values],
enabled: i.enabled
}
}), {});
const target = orig.map(itm => ({
...itm,
values: itm.values.map(it2 => ({
...it2,
selected: deltaMapper[itm.name].values.includes(it2.value) || false
})),
enabled: deltaMapper[itm.name].enabled || false
}));
debug && console.log('Merged Target:\n', target);
return JSON.stringify(target);
};
getTargetJSON(delta, orig); // method call
Approach / Explanation:
We breakdown the problem into smaller ones.
First, generate a map using the source (named 'delta' in
code-snippet)
Next, iterate through the target (named 'orig') and utilize the
map (created above) to determine whether value is 'selected' and
item is 'enabled'.

Searching for a value inside an array of objects based on a key and returning a sibling's value

I have a key value that I am searching for. Each object has the a key of key for each object in the array. I would like to match the term I am searching for to the value of the key and return the value for the sibling with a key of name.
Here is a sample object:
{
"test1": {
"functions": {
"function1": {
"inputs": [
{
"key": "key1",
"name": "name1"
},
{
"key": "key2",
"name": "name3"
},
{
"key": "key3",
"name": "name3"
}
]
},
"function2": {
"inputs": [
{
"key": "key4",
"name": "name4"
},
{
"key": "key5",
"name": "name5"
},
{
"key": "key6",
"name": "name6"
}
]
}
}
}
}
Let's say I want to find the name of an input with a key of key4. How would I achieve this in javascript?
Is this what you want?
var yourObject = {
"inputs": [
{
"key": "callset_name",
"name": "Callset Name",
"type": "STRING",
"required": false,
"fromPrevious": false,
"internalOnly": false
},
{
"key": "reference_genome",
"name": "Reference Genome",
"description": "A reference genome.",
"type": "DATASET",
"required": true,
"fromPrevious": false,
"internalOnly": false,
"constraints": {
"dataset": {
"types": [
"REFERENCE_GENOME"
],
"components": [
"bwa_reference_genome"
]
}
}
},
{
"key": "bam",
"name": "BAM",
"type": "FILE",
"required": true,
"fromPrevious": true,
"internalOnly": false,
"constraints": {
"file": {
"types": [
"BAM"
],
"indexedBy": "bai"
}
}
},
{
"key": "bai",
"name": "BAM Index",
"type": "FILE",
"required": true,
"fromPrevious": true,
"internalOnly": false,
"constraints": {
"file": {
"types": [
"BAM_INDEX"
]
}
}
},
{
"key": "dbsnp_vcf",
"name": "dbSNP VCF",
"description": "Single Nucleotide Polymorphism Database",
"type": "FILE",
"required": false,
"fromPrevious": false,
"internalOnly": false,
"constraints": {
"file": {
"types": [
"VCF"
],
"indexedBy": "dbsnp_vcf_index"
}
}
},
{
"key": "dbsnp_vcf_index",
"name": "dbSNP VCF Index",
"description": "Single Nucleotide Polymorphism Database Index",
"type": "FILE",
"required": false,
"fromPrevious": false,
"internalOnly": false,
"constraints": {
"file": {
"types": [
"VCF_INDEX",
"VCF_IDX"
]
}
}
}
]
};
function getData(key, outputKey) {
const output = yourObject.inputs.find(data => data.key === key);
if (output && output.hasOwnProperty(outputKey)) {
return output[outputKey];
}
return;
}
console.log(getData('reference_genome', 'name'));

Iterate Json and get last elements

i want to iterate json to get last element. I have tried to find the json length but length is showing 296 something.there is something i don't know ..how to iterate.
Iterate Json and get last elements id: 005 and text: GHI. I am trying to do in this way.
JQuery
var json= ( JSON.stringify($(target).select2('data')) );
alert(selections.length);
$.each($.parseJSON(json), function(key,value){
var id = this.id;
var text = this.text;
console.log(id +" "+text);
});
JSON
[
{
"id": "001",
"text": "DEF",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "002",
"text": "JKL",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "003",
"text": "MNO",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "004",
"text": "ABC",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "005",
"text": "GHI",
"element": [
{
}
],
"disabled": false,
"locked": false
}
]
Store your JSON in a variable
Make use of varName.length-1 to reach the last element in the array
Demo
var json = [{
"id": "001",
"text": "DEF",
"element": [{
}],
"disabled": false,
"locked": false
}, {
"id": "002",
"text": "JKL",
"element": [{
}],
"disabled": false,
"locked": false
}, {
"id": "003",
"text": "MNO",
"element": [{
}],
"disabled": false,
"locked": false
}, {
"id": "004",
"text": "ABC",
"element": [{
}],
"disabled": false,
"locked": false
}, {
"id": "005",
"text": "GHI",
"element": [{
}],
"disabled": false,
"locked": false
}];
var $last = json[json.length - 1];
alert($last.id);
alert($last.text);
You are dealing with a Javascript array. Using length to get the last index will indeed work:
var json = JSON.stringify( $(target).select2('data') );
var lastObject = json[json.length - 1];
var id = lastObject.id;
var text = lastObject.text;
console.log( id + " " + text );
Remember that indexes start with 0, so you must subtract 1 from the length to get the desired index.
var h = [
{
"id": "001",
"text": "DEF",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "002",
"text": "JKL",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "003",
"text": "MNO",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "004",
"text": "ABC",
"element": [
{
}
],
"disabled": false,
"locked": false
},
{
"id": "005",
"text": "GHI",
"element": [
{
}
],
"disabled": false,
"locked": false
}
];
var len = h.length;
console.log(len); //prints 5
console.log(h[len-1].id); //prints 005
console.log(h[len-1].text); //prints GHI

Categories