Build tree from flat array using two data tables in Javascript - javascript

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; }

Related

Look up values in an array using looping forEach Google Apps Script Javascript

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));

Sort Array of Objects Childs to new Array with Objects

I'm programming a small vue.js App and need to convert an array to a new one and sort them.
The array of objects I get from the backend server looks like that:
var arr =
[
{
"id": 1,
"name": "Name1",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
},
{
"id": 2,
"name": "Name2",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 11
}
}
},
{
"id": 3,
"name": "Name3",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
}
]
console.log(arr)
But I need a new array, that is sorted like that:
var newArr =
[
{
"mainId": 10,
"parents": {
"id": 1,
"name": "Name1"
}
},
{
"mainId": 11,
"parents": [
{
"id": 2,
"name": "Name2"
},
{
"id": 3,
"name": "Name3"
}
]
}
]
What is the best way to implement this?
You could group the items with the help of a Map.
var array = [{ id: 1, name: "Name1", parents: { someOtherTings: "Test", partentOfParent: { mainId: 10 } } }, { id: 2, name: "Name2", parents: { someOtherTings: "Test", partentOfParent: { mainId: 11 } } }, { id: 3, name: "Name3", parents: { someOtherTings: "Test", partentOfParent: { mainId: 10 } } }],
result = Array.from(
array.reduce(
(m, { id, name, parents: { partentOfParent: { mainId } } }) =>
m.set(mainId, [...(m.get(mainId) || []), { id, name }]),
new Map
),
([mainId, parents]) => ({ mainId, parents })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You just need a combination of map to create a new array and then sort it based on the mainId value
var arr = [{
"id": 1,
"name": "Name1",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
},
{
"id": 2,
"name": "Name2",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 11
}
}
},
{
"id": 3,
"name": "Name3",
"parents": {
"someOtherTings": "Test",
"partentOfParent": {
"mainId": 10
}
}
}
]
const newArr = arr.map(obj => ({
mainId: obj.parents.partentOfParent.mainId,
parents: {
id: obj.id,
name: obj.name
},
})).sort((a, b) => b - a);
console.log(newArr);

Query an object array to check if it contains an array of strings in mongoose

say i have the following inside my db:
knights
{
name: 'Knightley',
skills: [
{ name: 'sword', level: 2 },
{ name: 'shield', level: 1 }
]
},
{
name: 'Cowardly',
skills: [
{ name: 'sword', level: 1 },
{ name: 'shield', level: 5 }
]
}
and i want to return all knights with skills of sword and shield.
something like this (pseudo):
Knight.find({ skills.name: which contains ['sword', 'shield'] })
how do i do this kind of query?
thanks!
You need to use $elemMatch to find inside the array with $in operator
db.collection.find({
skills: {
$elemMatch: {
name: { $in: ["sword", "shield"] }
}
}
})
Output
[
{
"name": "Knightley",
"skills": [
{
"level": 2,
"name": "sword"
},
{
"level": 1,
"name": "shield"
}
]
},
{
"name": "Cowardly",
"skills": [
{
"level": 1,
"name": "sword"
},
{
"level": 5,
"name": "shield"
}
]
}
]
Check it here

Javascript(NodeJs) - Conversion of Arrays and Objects to bulk insert in mysql(Sequelize)

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);

Filtering nested array of objects

I have the following events array. For every event there is a hash as {organisation name: [{participant 1}, {participant 2}, {...}]}
"events": [
{
"Org A": [
{
"event_id": 1,
"id": 432,
"name": "John Doe",
"role": null
},
{
"event_id": 1,
"id": 312,
"name": "Jane Mow",
"role": [
"speaker"
]
}
],
}
],
I would like to filter this events array to only contain participants whose role contains speaker.
Also, when there are no speakers in the participant array, the respective organisation entry needs to be removed from the Hash (object).
To filter the array of objects, I tried using this:
_.each(events, function(event){
_.filter(event, function(p) {
_.filter(p, function(d){
return _.some(d.role, function(r){
return r == "speaker"})
})
})
})
This however doesn't work.
Try this
var data = {
"events": [{
"Org A": [{
"event_id": 1,
"id": 432,
"name": "John Doe",
"role": null
}, {
"event_id": 1,
"id": 312,
"name": "Jane Mow",
"role": [
"speaker"
]
}],
"Org B": [],
"Org C": []
}]
};
var SPEAKER = 'speaker';
var result = _.map(data.events, function (events) {
return _.chain(events)
.mapObject(function (value, key) {
return _.filter(value, function (event) {
return _.isArray(event.role) && _.indexOf(event.role, SPEAKER) >= 0;
});
})
.pick(function (value) {
return value && value.length;
})
.value();
})
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>

Categories