I have a javascript variable with the following structure
var recurse = {
level_0: [
{
level_1 : [
{
level_2_0 : [
{
level_3_0: {
valid: true,
available: false
}
}, {
level_3_1 : {
valid: true,
available: true
}
}]
}, {
level_2_1 : [
{
level_3_0: {
valid: true,
available: false
}
}, {
level_3_1 : {
valid: true,
available: true
}
}]
}]
}]
}
Final required output structure
var recurse = {
name: "level_0",
property: [
{
name: "level_1",
property: [
{
name: "level_2_0",
property: [
{
name: "level_3_0",
property: {
valid: true,
available: false
}
}, {
name: "level_3_1",
property: {
valid: true,
available: true
}
}]
}, {
name: "level_2_1",
property: [
{
name: "level_3_0",
property: {
valid: true,
available: false
}
}, {
name: "level_3_1",
property: {
valid: true,
available: true
}
}]
}]
}]
}
Facing problem with cloning and updating the structure for this nested object using generic methods.
How can I achieve the required final object structure using simple javascript or reactjs properties.
Which is the most appropriate method to clone a javascript object?
Note: the object names- level_0, level_1 level_2_0 could be random or dynamic.
You can write a simple recursive function that recurses on the item if the item value is an array like below
var recurse = {
level_0: [
{
level_1 : [
{
level_2_0 : [
{
level_3_0: {
valid: true,
available: false
}
}, {
level_3_1 : {
valid: true,
available: true
}
}]
}, {
level_2_1 : [
{
level_3_0: {
valid: true,
available: false
}
}, {
level_3_1 : {
valid: true,
available: true
}
}]
}]
}]
}
function format(data) {
return Object.entries(data).map(([key, value]) => {
if(Array.isArray(value))
return {
name: key,
property: [].concat(...value.map(item => format(item)))
}
return {
name: key,
property: value
}
})
}
console.log(format(recurse));
You can transform it with something like this:
const transform = (tree) =>
Object (tree) === tree
? Object .entries (tree) .map (([name, properties]) => ({
name,
properties: Array .isArray (properties) ? properties .map (transform) : properties
})) [0] // This is a strage thing to do with an object! The original data structure is odd.
: tree
var recurse = {level_0: [{level_1: [{level_2_0: [{level_3_0: {valid: true, available: false}}, {level_3_1: {valid: true, available: true}}]}, {level_2_1: [{level_3_0: {valid: true, available: false}}, {level_3_1: {valid: true, available: true}}]}]}]}
console .log (transform (recurse))
.as-console-wrapper {min-height: 100% !important; top: 0}
But the data structure you start with is quite odd. Each level of nesting except the innermost can only have a single property. Is that really how your data comes to you? It's a strange use of objects. (Then again, you are asking about how to reforat it...)
The [0] on the sixth line of the above deals with that oddity of the input.
Related
What is the correct way to modify json response ,
My goal is to display all the MaintroomName belonging to the same Plsectn
This is the function that needs to modify to get the same structure
which I mentioned below that I am interested in reaching.
useEffect(() => {
BtpBridgeModule.loadDataFromSdk(
'GushSet',
[],
{ PlantID: userData.plant, LocationID: userData.LocationID },
undefined,
0,
).then(function (dataResolved) {
let aResults = JSON.parse(dataResolved).value;
});
}, [userData.LocationID, userData.plant]);
The json look like this :
[
{
"Maintroom":"221",
"MaintroomName":"gogi",
"Plsectn":"22",
"PlsectnName":"pardehan"
},
{
"Maintroom":"222",
"MaintroomName":"nahaleymenash",
"Plsectn":"22",
"PlsectnName":"pardehan"
},
{
"Maintroom":"231",
"MaintroomName":"gvul",
"Plsectn":"23",
"PlsectnName":"meshulash"
},
{
"Maintroom":"232",
"MaintroomName":"daro",
"Plsectn":"23",
"PlsectnName":"meshulash"
},
]
I wanna change it to this structure :
[
{
title: PlsectnName,
checked: false,
data: [
{ key: MaintroomName, value: false, checked: false },
{ key: MaintroomName, value: false, checked: false },
{ key: MaintroomName, value: false, checked: false },
{ key: MaintroomName, value: false, checked: false },
],
},
{
title: PlsectnName,
checked: false,
data: [
{ key: MaintroomName, value: false, checked: false },
{ key: MaintroomName, value: false, checked: false },
{ key: MaintroomName, value: false, checked: false },
],
},
]
Note - each Plsectn can have a dynamic number of MaintroomName.
Algorithm to sort your data
// Your response data
const data = [
{
"Maintroom":"221",
"MaintroomName":"gogi",
"Plsectn":"22",
"PlsectnName":"pardehan"
},
{
"Maintroom":"222",
"MaintroomName":"nahaleymenash",
"Plsectn":"22",
"PlsectnName":"pardehan"
},
{
"Maintroom":"231",
"MaintroomName":"gvul",
"Plsectn":"23",
"PlsectnName":"meshulash"
},
{
"Maintroom":"232",
"MaintroomName":"daro",
"Plsectn":"23",
"PlsectnName":"meshulash"
},
];
// Variable to track duplicate keys (PlsectnName)
let keys = [];
// Result after sorting the data
let result = [];
// Algorithm to sort the data
data.forEach((obj) => {
if(!keys.includes(obj.PlsectnName)){
result.push({
title: obj.PlsectnName,
checked: false,
data: [
{ key: obj.MaintroomName, value: obj.Maintroom, checked: false }
]
});
keys.push(obj.PlsectnName);
}
else {
result.forEach((subObj,index) => {
if(subObj.title == obj.PlsectnName){
subObj.data = [...subObj.data, { key: obj.MaintroomName, value: obj.Maintroom, checked: false }]
result[index] = subObj;
}
});
}
})
// Log the result
console.log(result)
(Note: If you want to set the value as false then change value: obj.Maintroom to value: false)
Implementing the Algorithm in your useEffect function.
// Algorithm as function to sort your data
const sortData = (data) => {
// Variable to track duplicate keys (PlsectnName)
let keys = [];
// Result after sorting the data
let result = [];
// Algorithm to sort the data
data.forEach((obj) => {
if(!keys.includes(obj.PlsectnName)){
result.push({
title: obj.PlsectnName,
checked: false,
data: [
{ key: obj.MaintroomName, value: obj.Maintroom, checked: false }
]
});
keys.push(obj.PlsectnName);
}
else {
result.forEach((subObj,index) => {
if(subObj.title == obj.PlsectnName){
subObj.data = [...subObj.data, { key: obj.MaintroomName, value: obj.Maintroom, checked: false }]
result[index] = subObj;
}
});
}
})
// return the result
return result;
}
// Your function
useEffect(() => {
BtpBridgeModule.loadDataFromSdk(
'GushSet',
[],
{ PlantID: userData.plant, LocationID: userData.LocationID },
undefined,
0,
).then(function (dataResolved) {
let aResults = JSON.parse(dataResolved).value;
// Added code
let sortedResult = sortData(aResults)
// Here sortedResult is your final data
});
}, [userData.LocationID, userData.plant]);
I am having a hard time trying to convert an object supplied in a specific format from API into a target format using javascript. Please note that in the target format, the false values are not present. This is intentional. Can someone please help by showing how I can do the this kind of conversion. Thank you
// Original format
const rules= [
{
dealer: {
view: true,
edit: false,
add: false
},
franchise: {
view: true,
edit: true,
add: true
},
branch: {
view: true,
edit: false,
add: false
}
}
]
// Target format
const rules = [
{
actions: ["view"],
subject: ["dealer"]
},
{
actions: ["view"],
subject: ["franchise"]
},
{
actions: ["edit"],
subject: ["franchise"]
},
{
actions: ["add"],
subject: ["franchise"]
},
{
actions: ["view"],
subject: ["branch"]
}
];
I implemented mapping function which take each item and map it according to the value if true
let rules = [
{
dealer: {
view: true,
edit: false,
add: false
},
franchise: {
view: true,
edit: true,
add: true
},
branch: {
view: true,
edit: false,
add: false
}
}
]
rules = rules.map(item => {
const keys = Object.keys(item);
let mappedItem = []
keys.forEach(key => {
for (const property in item[key]) {
if (item[key][property]) {
mappedItem.push({ subject: [key], actions: [property] })
}
}
})
return mappedItem;
});
let rules= [
{
dealer: {
view: true,
edit: false,
add: false
},
franchise: {
view: true,
edit: true,
add: true
},
branch: {
view: true,
edit: false,
add: false
}
}
];
const result = rules.map(obj => Object.keys(obj).map(k => ({
subject: [k],
actions: Object.keys(obj[k]).filter(action => obj[k][action])
})).reduce((acc, cur) => ([
...acc,
...cur.actions.map(a => ({subject: cur.subject, actions: [a]}))
]),[]))
console.log(result);
I have a config.ts file with following content:
export const keyOrders: {} = {
"aa": { active: true, order: 0 },
"bb": { active: true, order: 1 },
"cc": { active: true, order: 2 },
"dd": { active: true, order: 3 },
"ee": { active: false, order: 4 },
"ff": { active: true, order: 5 }
};
I am trying to push to array if active is only true. I have tried following code which is pushing key if active is true but if active is false then it is returning "undefined"
public keys = [];
public keyOrders = keyOrders;
ngOnInit() {
this.keys = Object.entries(this.keyOrders).map((a: any) => {
if(a[1].active == 'true') {
return a[0];
}
});
}
Use filter followed by map.
If you want to sort the items based on their order property, use sort before map.
filter will only keep items passing the predicate, in this case a truthy active property. Then map will map this array to the keys.
In your case, using map will give you an array of the same length, you must filter it first.
type Order = { active: boolean, order: number };
const keyOrders: { [key: string]: Order } = {
"aa": { active: true, order: 0 },
"bb": { active: true, order: 1 },
"cc": { active: true, order: 2 },
"dd": { active: true, order: 3 },
"ee": { active: false, order: 4 },
"ff": { active: true, order: 5 }
}
this.keys = Object.entries(this.keyOrders)
.filter(([_, val]) => val.active)
.sort((a, b) => a[1].order - b[1].order)
.map(([key, _]) => key);
For the types to work out, Object.entries() must be recognized by Typescript, for this, add "lib": [ "es2017.object" ] in your tsconfig.json file.
Here is a JavaScript demo (types stripped):
const keyOrders = {
"aa": { active: true, order: 0 },
"bb": { active: true, order: 1 },
"cc": { active: true, order: 2 },
"dd": { active: true, order: 3 },
"ee": { active: false, order: 4 },
"ff": { active: true, order: 5 }
};
const keys = Object.entries(keyOrders)
.filter(([_, val]) => val.active)
.sort((a, b) => a[1].order - b[1].order)
.map(([key, _]) => key);
console.log(keys);
i have an array like so
sections: [
{
editing: false,
id: 1234,
rows: [
{
editing: false,
id: 3435,
columns: [
{
id: 1535,
elements: [
{
editing: true,
id: 4849
}
]
}
]
}
]
},
]
and im trying to find any object with a property editing is true.
the following code works, but only for sections and rows, but for some reason its not finding the property in the elements array
this is the js, using lodash
return _(state.sections)
.thru(function(coll) {
return _.union(coll, _.map(coll, 'rows'));
})
.thru(function(coll2) {
return _.union(coll2, _.map(coll2, 'columns'));
})
.thru(function(coll3) {
return _.union(coll3, _.map(coll3, 'elements'));
})
.flatten()
.find({ editing: true });
After the first thru the intermediate result of the chain is an array consisting of an object and an array:
[
{ id: 1234, .... },
[ { id: 3435, ... } ]
]
To get what you want, replace the map calls with flatMap which would then returns this after the first thru:
[
{ id: 1234, .... },
{ id: 3435, ... }
]
As there will be undefined returned in the intermediate results if the objects don't have columns or elements, you will need to use compact to remove these before performing the find:
return _(state.sections)
.thru(function(coll) {
return _.union(coll, _.flatMap(coll, 'rows'));
})
.thru(function(coll2) {
return _.union(coll2, _.flatMap(coll2, 'columns'));
})
.thru(function(coll3) {
return _.union(coll3, _.flatMap(coll3, 'elements'));
})
.compact()
.find({ editing: true });
I am trying to pull an array from a different collection using collection2. I have been able to do this with objects using the following example for users:
users: {
type: String,
label: "Inspector",
optional: true,
autoform: {
firstOption: 'Choose an Inspector',
options: function() {
return Meteor.users.find({}, {
sort: {
profile: 1,
firstName: 1
}
}).map(function(c) {
return {
label: c.profile.firstName + " " + c.profile.lastName,
value: c._id
};
});
}
}
},
I would like to do the same but for an array of objects. Here is what the source data looks like:
{
"_id": "xDkso4FXHt63K7evG",
"AboveGroundSections": [{
"sectionName": "one"
}, {
"sectionName": "two"
}],
"AboveGroundItems": [{
"itemSection": "one",
"itemDescription": "dfgsdfg",
"itemCode": "dsfgsdg"
}, {
"itemSection": "two",
"itemDescription": "sdfgsdfg",
"itemCode": "sdfgsdgfsd"
}]
}
Here is what my function looks like:
agSection: {
type: String,
optional: true,
autoform: {
firstOption: 'Select A Section Type',
options: function() {
return TemplateData.find({}, {
sort: {
AboveGroundSections: 1,
sectionName: [0]
}
}).map(function(c) {
return {
label: c.AboveGroundSections.sectionName,
value: c.AboveGroundSections.sectionName
}
});
}
}
},
I know this, it's just not pulling the data for me. I am sure, I am just missing something small. I am trying to pull all objects within the AboveGroundSection array.
Your .map() is iterating over the set of documents but not over the arrays inside each document. Also I don't think your sorting is going to work the way you hope because of the inner nesting.
Try:
agSection: {
type: String,
optional: true,
autoform: {
firstOption: 'Select A Section Type',
options() {
let opt = [];
TemplateData.find().forEach(c => {
c.AboveGroundSections.forEach(s => { opt.push(s.sectionName) });
});
return opt.sort().map(o => { return { label: o, value: o } });
}
}
},
Also if your AboveGroundSections array only has a single key per element then you can simplify:
"AboveGroundSections": [
{ "sectionName": "one" },
{ "sectionName": "two" }
]
To:
"AboveGroundSections": [
"one",
"two"
]