Related
Just want to remove all the items other than 14 from the parentId: 1001 and add that item to another object.
I want to filter the array without affecting the source array.
var Data = [{
"id": 1001,
"text": "A",
"items": [
{ "id": 13, "text": "Thirteen" },
{ "id": 14, "text": "Fourteen" },
{ "id": 15, "text": "Fifteen", }
]
},
{
"id": 1002,
"text": "B",
"items": [
{ "id": 21, "text": "TwentyOne" },
{ "id": 22, "text": "TwentyTwo" },
{ "id": 23, "text": "TwentyThree", }
]
}
]
var childId = 14;
Data.items.filter((x) => {
return x.id != childId;
})
//this is affecting the source array (Data)
//after searching on internet found a solution
Data.items.filter((x) => {
return x.id childId;
}).map(function(x) {
return x
});
Your Data has no items property: it is an array, so you actually have Data[0].items, Data[1].items, ...
NB: it is common practice to use camelCase for such variable names, and reserve PascalCase for constructors/classes
Here is how you could do it:
const data = [{"id": 1001,"text": "A","items": [{ "id": 13, "text": "Thirteen" }, { "id": 14, "text": "Fourteen" }, { "id": 15, "text": "Fifteen", }]},{"id": 1002,"text": "B","items": [{ "id": 21, "text": "TwentyOne" }, { "id": 22, "text": "TwentyTwo" }, { "id": 23, "text": "TwentyThree", }]}]
const childId = 14;
const newData = data.map(obj => ({
...obj,
items: obj.items.filter(x => x.id != childId)
}));
console.log(newData);
As you want to filter out a few items from an array object and want to add those into another object.
You can also achieve this requirement by doing a deep copy of an original array with the help of structuredClone() API and then iterating it using Array#forEach method.
Live demo :
const data=[
{
"id":1001,
"text":"A",
"items":[
{
"id":13,
"text":"Thirteen"
},
{
"id":14,
"text":"Fourteen"
},
{
"id":15,
"text":"Fifteen",
}
]
},
{
"id":1002,
"text":"B",
"items":[
{
"id":21,
"text":"TwentyOne"
},
{
"id":22,
"text":"TwentyTwo"
},
{
"id":23,
"text":"TwentyThree",
}
]
}
];
const clone = structuredClone(data);
let remainingItems = [];
clone.forEach(obj => {
if (obj.id === 1001) {
remainingItems = obj.items.filter(({ id }) => id !== 14);
obj.items = obj.items.filter(({ id }) => id === 14);
} else {
obj.items = [...obj.items, ...remainingItems];
}
})
console.log('cloned data_____', clone);
console.log('source data_____', data);
So there is array of objects of below format
let inputs = [
{
"id": "614344d9d9c21c0001e6af2e",
"groupName": "Unassigned",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f2e",
"groupName": "P1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f38",
"groupName": "K1",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f3e",
"groupName": "A2",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f40",
"groupName": "G1",
"parentGroup": "P2"
},
{
"id": "614447da152f69c3c1d52f46",
"groupName": "F1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f30",
"groupName": "P2",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f36",
"groupName": "C2",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f3c",
"groupName": "A1",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f34",
"groupName": "C1",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f32",
"groupName": "P3",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f3a",
"groupName": "K2",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f42",
"groupName": "GG1",
"parentGroup": "G1"
},
{
"id": "614447da152f69c3c1d52f44",
"groupName": "GGG1",
"parentGroup": "GG1"
}
]
i am trying to create a tree structure of format
{name:'p1',children:[{name:'c1':children:[]}]}
so i sorted all the elements of given array considering element with parentGroup as "null" to be at the top of the array.
let finalArr = [];
inputs.sort((a,b)=> (a.parentGroup === "null") ? -1 : 1);
And for each element of the inputs array, i was iterating below logic
inputs.forEach(ele => {
if(ele.parentGroup === "null"){
let child= {name:ele.groupName,children:[]};
finalArr.push(child);
}else{
finalArr.forEach(item => {
this.findNode(item,ele);
})
}
});
If the 'parentGroup' of element is "null", then create a leaf kind of obj and push the element to 'finalArr' array
Else, then iterate across all the elements of 'finalArr' over a recursion function
public findNode(ele, obj){
if(ele.children.length === 0){
if(ele.name === obj.parentGroup){
let child = {name:obj.groupName, children:[]};
ele.children.push(child);
}
}else{
let j = ele.children.length-1;
this.findNode(ele.children[j--],obj);
}
}
This recursion function will check the element has children or not, if no children, then compare the parentGroup of given obj, with name of element from 'FinalArr'.
if so ,push the current obj to the children of the element of finalArr.
else, that is, when children has more elements, the same recursion will be triggered until depth of the element is reached.
With this i tought i would make a tree structure with given inputs array, but when a parent has more children, of same level, this logic fails,
so the inputs array has 'c1' which is a child of 'p1', but nly the child 'c2' resides, not sure the what is that i missed.
You could take a standard algorithm for getting a tree with given data
const
getTree = (data, id, parent, root, fn = o => o) => {
var t = {};
data.forEach(o => ((t[o[parent]] ??= {}).children ??= []).push(Object.assign(t[o[id]] = t[o[id]] || {}, fn(o))));
return t[root].children;
},
data = [{ id: "614344d9d9c21c0001e6af2e", groupName: "Unassigned", parentGroup: "null" }, { id: "614447da152f69c3c1d52f2e", groupName: "P1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f38", groupName: "K1", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f3e", groupName: "A2", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f40", groupName: "G1", parentGroup: "P2" }, { id: "614447da152f69c3c1d52f46", groupName: "F1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f30", groupName: "P2", parentGroup: "null" }, { id: "614447da152f69c3c1d52f36", groupName: "C2", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f3c", groupName: "A1", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f34", groupName: "C1", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f32", groupName: "P3", parentGroup: "null" }, { id: "614447da152f69c3c1d52f3a", groupName: "K2", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f42", groupName: "GG1", parentGroup: "G1" }, { id: "614447da152f69c3c1d52f44", groupName: "GGG1", parentGroup: "GG1" }],
tree = getTree(data, 'groupName', 'parentGroup', null, ({ groupName: name }) => ({ name }));
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think the issue is how finalArr is used to generate the html elements.
When doing console.log(finalArr) it looks like the code block below. So it seems to me like the code you have to build the structure of finalArr is working fine.
// console.log(finalArr)
[
{ "name": "P3", "children": [] },
{
"name": "P2",
"children": [
{
"name": "G1",
"children": [
{ "name": "GG1", "children": [
{ "name": "GGG1", "children": [] }
]
}
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P1",
"children": [
{ "name": "C2", "children": [
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "Unassigned", "children": [] }
]
EDIT
As OP mentioned in the comment C1 was missing. I've introduced a root element that will have the finalArr as its children and changed the findNode to use a for loop instead of forEach. In this way we can also break when we find the node and not continue recursing.
As part of the initial sorting we will sort the inputs by parentGroup so we ensure that a childs parent is added in the tree structure before we try to find it with findNode.
I believe this produces the correct result:
inputs.sort((a, b) => (a.parentGroup === "null" ? -1 : 1));
// Sort by parentGroup
let root = inputs.pop();
let inputsDescending = [root];
let max = inputs.length * inputs.length;
let c = 0;
while (inputs.length > 0 && max > c) {
const child = inputs.pop();
const hasParentGroup = inputsDescending.find(
(parent) => parent.groupName === child.parentGroup
);
if (hasParentGroup || child.parentGroup === "null") {
inputsDescending.push(child);
} else {
inputs.unshift(child);
}
}
let rootEle = { name: "root", children: [] };
inputsDescending.forEach((obj) => {
if (obj.parentGroup === "null") {
let child = { name: obj.groupName, children: [] };
rootEle.children.push(child);
} else {
findNode(rootEle, obj);
}
});
function findNode(ele, obj) {
if (ele.name === obj.parentGroup) {
let child = { name: obj.groupName, children: [] };
ele.children.push(child);
return true;
} else {
const c = ele.children.length;
if (c > 0) {
for (let i = 0; c > i; i++) {
const found = findNode(ele.children[i], obj);
if (found) break;
}
}
}
}
const finalArr = rootEle.children;
Now finalArr looks like this:
[
{ "name": "Unassigned", "children": [] },
{
"name": "P1",
"children": [
{
"name": "C1",
"children": [
{ "name": "K1", "children": [] },
{ "name": "K2", "children": [] }
]
},
{
"name": "C2",
"children": [
{ "name": "A2", "children": [] },
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P2",
"children": [
{ "name": "G1", "children": [
{ "name": "GG1", "children": [] }
]
}
]
},
{ "name": "P3", "children": [] }
]
I have an object that looks like the following {key: id numbers}
var obj = {
"c4ecb": {id: [3]},
"a4269": {id: [34,36]},
"d76fa": {id: [54,55,60,61]},
"58cb5": {id: [67]}
}
How do I loop each above id in the following array, and return the label?
var response =
{
"success": true,
"data": [
{
"key": "c4ecb",
"name": "fruits",
"options": [
{
"label": "strawberry",
"id": 3
},
{
"label": "apple",
"id": 4
},
{
"label": "pineapple",
"id": 5
},
{
"label": "Other",
"id": 31
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "a4269",
"name": "vegetables",
"options": [
{
"label": "lettuce",
"id": 34
},
{
"label": "cucumber",
"id": 35
},
{
"label": "radish",
"id": 36
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "d76fa",
"name": "pasta",
"options": [
{
"label": "spaghetti",
"id": 54
},
{
"label": "rigatoni",
"id": 55
},
{
"label": "linguine",
"id": 56
},
{
"label": "lasagna",
"id": 60
},
{
"label": "fettuccine",
"id": 61
}
],
}
]
}
Finally, what I want to do is look up the key and return a string of id values.
For example, input c4ecb and output strawberry. Input a4269 and output lettuce, radish. Input d76fa and output "spaghetti, rigatoni, lasagna, fettuccine"
I think to join the multiple labels output into one string I could use something like
array.data.vegetables.map(vegetables => vegetables.value).join(', ')].toString();
So in the end I want to have something like
var fruits = [some code that outputs "strawberry"];
var vegetables = [some code that outputs "lettuce, radish"];
var pasta = [some code that outputs "spaghetti, rigatoni, lasagna, fettuccine"];
What I've tried so far:
The following loop will return the id only if there is one id to be called for: e.g. only in case one where {id: 3} but returns null in cases like {id: 34,36} (because it's looking for '34,36' in id, which doesn't exist - I need to look for each one individually.
response.data.forEach(({key, options}) => {
if (obj[key]) {
options.forEach(({id, label}) => {
if (id == obj[key].id) obj[key].label = label;
});
}
});
console.log(obj)
Filter the response object to focus on the category that matches the id.
Map over the options array and select the items which appear in obj[id].
Finally convert the filtered results to a string.
See filteredLabelsAsString() function below for implementation.
var obj = {
"c4ecb": {"id": [3]},
"a4269": {"id": [34,36]},
"d76fa": {"id": [54,55,60,61]},
"58cb5": {"id": [67]}
}
var response =
[{
"success": true,
"data": [
{
"key": "c4ecb",
"name": "fruits",
"options": [
{
"label": "strawberry",
"id": 3
},
{
"label": "apple",
"id": 4
},
{
"label": "pineapple",
"id": 5
},
{
"label": "Other",
"id": 31
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "a4269",
"name": "vegetables",
"options": [
{
"label": "lettuce",
"id": 34
},
{
"label": "cucumber",
"id": 35
},
{
"label": "radish",
"id": 36
}
],
}
]
},
{
"success": true,
"data": [
{
"key": "d76fa",
"name": "pasta",
"options": [
{
"label": "spaghetti",
"id": 54
},
{
"label": "rigatoni",
"id": 55
},
{
"label": "linguine",
"id": 56
},
{
"label": "lasagna",
"id": 60
},
{
"label": "fettuccine",
"id": 61
}
],
}
]
}];
function filteredLabelsAsString(obj_key, obj, content=response) {
// sanity check: obj must contain obj_key
if (Object.keys(obj).includes(obj_key)) {
return content.filter((item) => {
// filter content using value of obj_key
return item.data[0].key == obj_key;
}).map((item) => {
// item : { success: true, data: [] }
// map over options array
return item.data[0].options.map((opt) => {
// option : {id, label}
// return the label if the id is in the obj object's list
if (obj[item.data[0].key].id.includes(opt.id))
return opt.label;
}).filter((label) => {
// filter out empty items
return label !== undefined;
});
}).join(",");
}
// if obj does not contain obj_key return empty string
return "";
}
console.log("fruits: " + filteredLabelsAsString("c4ecb", obj));
console.log("vegetables: " + filteredLabelsAsString("a4269", obj));
console.log("pasta: " + filteredLabelsAsString("d76fa", obj));
I'm stuck with creating tree structure from a flat array using two Mock data tables in JSON.
the table should match the two unique id to determine the hierarchy between them.
JSON with Groups DB array looks like that:
{
"group": [
{
"groupName": "ROOT",
"id": 1
},
{
"groupName": "Family",
"id": 9
},
{
"groupName": "BestFriends!",
"id": 10
},
{
"groupName": "Cars",
"id": 4
},
{
"groupName": "funHouse",
"id": 3
}
]
};
JSON including Users array looks like that:
{
"user": [
{
"username": "StrongGoose",
"password": "sdff12fdsa",
"age": 31,
"id": 2
},
{
"username": "John",
"password": "sdjd34fffdsa",
"age": 31,
"id": 3
},
{
"username": "Mary",
"password": "sdfffdsa",
"age": 31,
"id": 4
}
]
};
this is how is the first data table looks like and determines the hierarchy between groups:
{
"GroupsToGroups": [
{
"1":[9,10]
},
{
"10":[3]
}
]
};
The second looks like that and determines which user belongs to which group:
{
"GroupsToUsers": [
{
"11":[2]
},
{
"3":[3]
},
{
"4":[4]
},
{
"10":[2]
},
{
"3":[3]
}
]
};
The Hierarchy should look like that, needs to be written to JSON
[
{
"type": "group",
"id": "1",
"name": "ROOT",
"items": [
{
"type": "group",
"id": "9",
"name": "Family",
"items": []
},
{
"type": "group",
"id": "10",
"name": "BestFriends!",
"items": [
{
"username": "StrongGoose",
"password": "sdff12fdsa",
"age": 31,
"id": 2
},
{
"type": "group",
"id": "3",
"name": "funHouse",
"items": [
{
"username": "John",
"password": "sdjd34fffdsa",
"age": 31,
"id": 3
},
{
"type": "group",
"id": "4",
"name": "Cars",
"items": [
{
"username": "Mary",
"password": "sdfffdsa",
"age": 31,
"id": 4
}
],
}
]
}
]
}
]
}
];
edit: i have tried to create a function with a recursion that finds the relevant related groups.
it works but i don't know how to combine the users.
function checkChildren(group) {
const allChildren = insideGroups[group.id];
if (!allChildren) return group;
const childGroups = allChildren.map((findChildrenID) => {
const indexGroups = groups.findIndex((subGroup) => subGroup.id ===
findChildrenID);
return checkChildren(groups[indexGroups]);
});
return Object.assign({}, group, {groups: childGroups});
}
You could take a hash table for the various types of data for a faster accesss without iterating the arrays of objects.
In the case of users, you need anyway a new object with new properties and renamed keys.
Then you need a new property for the root objects and add it to the groups.groups property to have the same access type for all levels.
Ath the end iterate first groups.users and then groups.groups to get all object and for the groups, take the children as well.
In the given data I commented the unused/duplicate data.
function getNodes(node) {
return [
...(hash.groups.users[node] || []).map(id => hash.user[id]),
...(hash.groups.groups[node] || []).map(id => Object.assign(hash.group[id], { children: getNodes(id) }))
];
}
var db = {
group: [
{ groupName: "ROOT", id: 1 },
{ groupName: "Family", id: 9 },
{ groupName: "BestFriends!", id: 10 },
{ groupName: "Cars", id: 4 },
{ groupName: "funHouse", id: 3 }
],
user: [
{ username: "StrongGoose", password: "sdff12fdsa", age: 31, id: 2 },
{ username: "John", password: "sdjd34fffdsa", age: 31, id: 3 },
{ username: "Mary", password: "sdfffdsa", age: 31, id: 4 }
],
GroupsToGroups: [
{ 1: [9, 10] }, // ok
{ 10: [3] }, // second
{ 3: [4] }
],
GroupsToUsers: [
//{ 11: [2] }, // never used
{ 3: [3] },
{ 4: [4] },
{ 10: [2] }, // first
//{ 3: [3] } // dupe
]
},
hash = {
group: Object.assign(...db.group.map(({ id, groupName: name, type = 'group' }) => ({ [id]: { type, id, name } }))),
user: Object.assign(...db.user.map(o => ({ [o.id]: o }))),
groups: {
groups: Object.assign(...db.GroupsToGroups, { root: db.group.filter(({ groupName }) => groupName === 'ROOT').map(({ id }) => id) }),
users: Object.assign(...db.GroupsToUsers)
}
},
result = getNodes('root');
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is my json:
{
"senderName": "ifelse",
"message": "Hi",
"groups": [
{
"id": 14,
"groupname": "Angular",
"contactgroups": [
{
"id": 1,
"contact": {
"id": 1,
"gsm": "123456789"
}
},
{
"id": 3,
"contact": {
"id": 2,
"gsm": "111111111"
}
}],
"select": true
}],
"draftData": {
"contacts": [
]
}
}
How to make the above json into:
[{phoneno: 123456789; sender: ifelse ; message: Hi},{phoneno: 11111111; sender: ifelse ; message: Hi}]
I want to take phoneno data from gsm object key
Which is best method to do this? for or forEach or anyother?
I guess, this is what you want. Use map to convert contactgroups to new array with phoneno.
var data = {
"senderName": "ifelse",
"message": "Hi",
"groups": [{
"id": 14,
"groupname": "Angular",
"contactgroups": [{
"id": 1,
"contact": {
"id": 1,
"gsm": "123456789"
}
},
{
"id": 3,
"contact": {
"id": 2,
"gsm": "111111111"
}
}
],
"select": true
}],
"draftData": {
"contacts": []
}
}
var result = data.groups[0].contactgroups.map(i => {
return {
phoneno: i.contact.gsm,
sender: data.senderName,
message: data.message
}
})
console.log(result);