Create Parent-Child tree JSON with IDs not following each other - javascript

I'm trying to create a tree with database records,
at first I used the following code :
Create Parent-Child tree JSON
Which worked fine, but since I can Insert and Delete nodes of the tree in my database, the function isn't working anymore.
As you can see, now I can have the first Element with for Id 90 and childrens width smaller Ids.
var arry = [{
"parentId": null,
"moduleId": 90
},
{
"parentId": 1,
"moduleId":65
},
{
"parentId": 1,
"moduleId": 91
},
{
"parentId": 65,
"moduleId": 66
},
{
"parentId": 66,
"moduleId": 79
},
{
"parentId": 90,
"moduleId": 1
}
];
fiddle:
https://jsfiddle.net/1c20hb7w/
Of course, I can't change IDs in my database (It would be too simple).
So I would like to know how to makes everything work, if you have a track to help me..
thanks in advance!

For a more complicated tree I'd suggest a recursive approach, as example:
var arry=[{parentId:null,moduleId:90},{parentId:1,moduleId:65},{parentId:1,moduleId:91},{parentId:65,moduleId:66},{parentId:66,moduleId:79},{parentId:90,moduleId:1}];
function recursiveTree(array) {
function getChildren(parents, input) {
return parents.map(parent => {
const children = input.filter(x => x.parentId === parent.moduleId);
parent.children = children;
if(children.length === 0) {
return parent;
} else {
parent.children = getChildren(children, input);
return parent;
}
})
}
const roots = array.filter(x => x.parentId === null);
return getChildren(roots, array);
}
var r = recursiveTree(arry)
console.log('array', r);
console.log('result', JSON.stringify(r))

Related

Unable to get blank properties and it's id from array of object

i want to get empty properties(only need to check role,group and subgroup) and it's id both in array of objects.
let tempdata = [
{
"id": 41,
"tool": "Artifactory",
"role": "",
"group": "Dish",
"subgroup": "Ehub test 009",
"subscriptionId": "artifactory-ehub-test-009"
},
{
"id": 4,
"tool": "Gitlab",
"role": "Owner",
"group": "IDP",
"subgroup": "IDP-Service-Templates",
"subscriptionId": "gitlab-51663585"
}
]
What i tried so far is this:
tempdata.filter(item=>item.group=='' || item.subgroup=='' || item.role=='').map(item=>item.id)
but this only gives my id [41] what i want is [{"id":41,"blank_properties":["role"]}]
Can somebody please help.
you can simply do it this way
tempdata.map((item)=>{
let d = [];
if(item.role === ''){
d.push('role')
}
if(item.group ===''){
d.push('group')
}
if(item.subgroup===''){
d.push('subgroup')
}
return {...item,'blank_prop':d}
})
tempdata.filter(item=>item.group=='' || item.subgroup=='' ||
item.role=='').map(item=>{
let temp=[];
if(item.group==='')temp.push('group')
if(item.role==='')temp.push('role')
if(item.subgroup==='')temp.push('subgroup')
if(item.subscriptionId==='')temp.push('subscriptionId')
if(item.tool==='')temp.push('tool')
return {id:item.id,blank_property:temp};})
I'm going to propose a more sophisticated solution, in case you're interested in additional ways to approach this problem:
let tempData =
[
{
"id": 41,
"tool": "Artifactory",
"role": "",
"group": "Dish",
"subgroup": "Ehub test 009",
"subscriptionId": "artifactory-ehub-test-009"
},
{
"id": 4,
"tool": "Gitlab",
"role": "Owner",
"group": "IDP",
"subgroup": "IDP-Service-Templates",
"subscriptionId": "gitlab-51663585"
},
];
// An array of all properties you want to check for blank strings
const propertiesToCheck = [ "group", "subgroup", "role" ];
result = tempData
.filter((item) =>
{
// Your original code was filtering the array of objects to
// JUST ones that have at least one of those properties set to ""
// So this filter does the same thing.
//
// If you DON'T actually want to outright remove ones that don't match this condition,
// then you can just remove this entire filter step.
// Iterate object keys and values
for (const [ key, value ] of Object.entries(item))
{
// If the key is not in the above array of propertiesToCheck,
// then skip it
if (propertiesToCheck.indexOf(key) == -1)
{
continue;
}
// If we encounter one of those properties and it's blank, return true
if (value == "")
{
return true;
}
}
// Return false if we get through all of the properties without encountering one that's blank
return false;
})
.map((item) =>
{
// Create an object to house the result in the manner you described
const result =
{
id: item.id,
blank_properties: [],
};
// Iterate the object keys and values again
for (const [ key, value ] of Object.entries(item))
{
// Same deal as before
if (propertiesToCheck.indexOf(key) == -1)
{
continue;
}
// Then, if the value is blank...
if (value == "")
{
// ...push its key to the blank_properties array
result.blank_properties.push(key);
}
}
// Return the result!
return result;
});
// Prints:
// [ { id: 41, blank_properties: [ 'role' ] } ]
console.log(result);

Nested list in component from array of objects

I'm searching for a little help/advice. I had a task to create a multiple nested list from array of object. I did this, got a expected result, but the problem was my code was very complicated and not clean for sure, because i did it by mapping, filtering, and again mapping, mapped arrays. This give me a lot of code, and i am pretty sure you can do it a lot of easier, that's why i am searching for help. I am using react(18.2.0), but even good methods for situations like that in vanilla js will be very helpfull for me.
So there is one json file with a lot of data, i give a example because there is like Array[500+] object inside.
"data": [
{
"categoryId": 1,
"name": "Football",
"lvl": 1,
"parent": 0,
},
{
"categoryId": 2,
"name": "Basketball",
"lvl": 1,
"parent": 0,
},
{
"categoryId": 3,
"name": "Bundesliga",
"lvl": 2,
"parent": 1,
},
{
"categoryId": 4,
"name": "NBA",
"lvl": 2,
"parent": 2,
},
{
"categoryId": 5,
"name": "Wizzards",
"lvl": 3,
"parent": 4,
},
{
"categoryId": 6,
"name": "Lakers",
"lvl": 3,
"parent": 4,
},
.....and more
If parent === categoryId it means that it's children.
So the result component should give something like that:
- Football
- Bundesliga
- Basketball
- NBA
- Wizzards
- Lakers
I will be happy if you give me some good practices, advices about situations like that. Should i use recursion or what? :)
If you wanted to write this recursively, you could write it something like this:
const recursive = function(data, node, current, max) {
if(current > max) {
return {};
}
data.forEach( d => {
if(!node.children) {
node.children = [];
}
if(d.lvl === current && (d.parent === node.categoryId || current === 1)) {
node.children.push(d);
recursive(data, d, current+1, max)
}
});
}
let newObj = {};
let highestLevel = 1;
data.forEach(d => {
if(d.lvl > highestLevel) {
highestLevel = d.lvl;
}
})
recursive(data, newObj, 1, highestLevel)
I wrote this in playcode.io so that you can see it working: https://playcode.io/926085
The output is the entire objects, nested. But you can then print just the names from the resulting nested structure.
I don't think that this solution is the most optimal one, as far as time complexity goes. But it's a recursive example of how to solve the problem.
I'm open to someone optimizing this solution, as I am also interested in this problem.
UPDATE
I had a friend work on a solution. He optimized so that I think its O(n): https://playcode.io/926145/
const f = (input, map = {}) => {
input.forEach(d => {
const me = map[d.categoryId]
if(!me) {
map = {...map, [d.categoryId]: [] }
}
const siblings = map[d.parent]
if(siblings) {
map = {...map, [d.parent]: [...siblings, d]}
} else {
map = {...map, [d.parent]: [d]}
}
})
return map
}
const print = (map, input, toPrint, indent = 0) => {
toPrint.forEach(p => {
const ind = " ".repeat(indent)
console.log(`${ind} - ${p.name}`)
print(map, input, map[p.categoryId], indent + 2)
})
}
const map = f(data.data)
print(map, data.data, map[0])

Filtering and storing and finding parent child relationship in elements of array [duplicate]

This question already has answers here:
How to find a node in a tree with JavaScript
(19 answers)
Javascript - Find path to object reference in nested object
(3 answers)
Closed 1 year ago.
I am working on an angular application. My data is as follows
data= [
{
"id": 2,
"name": "Jamie",
"objectId": 200,
"parentId": null,
"children": [
{
"id": 98,
"name": "Rose",
"objectId": 100,
"parentId": 200,
"children": [
{
"id": 1212,
"name": "julie",
"objectId": 500,
"parentId": 100,
"children": []
}
]
},
{
"id": 67,
"name": "Kosy",
"objectId": 700,
"parentId": 200,
"children": []
}
]
}
]
I will be having input id and name. Suppose in my method I get id as 1212 and name as "julie". So I want to go to that node whose id is 1212 and name is equal to
"julie", once this condition is met. I need to check parentId in children is equal to objectId in parent till parentId becomes null.
If parent id becomes null then it is considered as last node and then I want to have my data in the array in following format. For id 1212 and name
"julie" resultArray is
resultArray = ["Jamie/Rose/Julie "]. Data starting from parent to children separated by slash.
Another example is if I get id as 67 and name "Kosy". then result array will be
resultArray = ["Jamie/Kosy"]
As parentId of Kosy is 200 and ObjectId of Jamie is 200, which indicate that Jamie is parent of Kosy, that's why data should look like this. want to have dynamic code as at run time data can be huge but structure and logic will be same as mentioned above
How can I do this
I wrote the code for this problem. Please try the following code. This is one of the typical tree-search problem. One point what sets it apart from traditional tree search is checking its parent. That was easily solved here.
const data = [
{
"id": 2,
"name": "Jamie",
"objectId": 200,
"parentId": null,
"children": [
{
"id": 98,
"name": "Rose",
"objectId": 100,
"parentId": 200,
"children": [
{
"id": 1212,
"name": "julie",
"objectId": 500,
"parentId": 100,
"children": []
}
]
},
{
"id": 67,
"name": "Kosy",
"objectId": 700,
"parentId": 200,
"children": []
}
]
}
];
// function that search the target in a node(not a array)
// In order for this function to return true, id comparison from the final node to this node should be passed as well
const findInNode = (node, id, name, output) => {
if (node.name === name && node.id === id) { // self test
return true;
} else {
const children = node.children;
if (!children) return false;
// find in children
for (let child of children) {
// output.paths is the current search path
output.paths.push(child.name);
if (findInNode(child, id, name, output)) {
// if found, compare the self objectId and child's parentId
return child.parentId === node.objectId;
}
output.paths.pop();
}
}
}
// function that search the target in an array, for use at the top-most level
const findInArray = (nodes, id, name, output) => {
for (let node of nodes) {
output.paths.push(node.name);
if (findInNode(node, id, name, output)) {
if (!node.parentId) {
output.found = true;
break;
}
}
output.paths.pop();
}
}
output = { paths: [], found: false };
findInArray(data, 1212, 'julie', output);
console.log(output.found);
console.log(output.paths.join('/'));

Javascript - Get occurence of json array with ESLINT 6

I can't set up an algo that counts my occurrences while respecting ESlint's 6 standards in javascript.
My input table is :
[
{
"id": 2,
"name": "Health",
"color": "0190fe"
},
{
"id": 3,
"name": "Agriculture",
"color": "0190fe"
},
{
"id": 1,
"name": "Urban planning",
"color": "0190fe"
},
{
"id": 1,
"name": "Urban planning",
"color": "0190fe"
}
]
And i want to get :
{"Urban planning": 2, "Health": 1, ...}
But that does not work with ESLINT / REACT compilation...
This is my code :
const jsonToIterate = *'MyPreviousInputJson'*
const names = []
jsonToIterate.map(item => (names.push(item.name)))
const count = []
names.forEach(item => {
if (count[item]){
count.push({text: item, value: 1})
} else {
count.forEach(function(top){top.text === item ? top.value =+ 1 : null})
}
})
Thank you so much
Well, you want an object in the end, not an array, so count should be {}. I also wouldn't use map if you're not actually returning anything from the call. You can use reduce for this:
let counts = topicsSort.reduce((p, c, i, a) => {
if (!p.hasOwnProperty(c.name)) p[c.name] = 0;
p[c.name]++;
return p;
}, {});
I'm half exppecting someone to close this as a duplicate because all you've asked for is a frequency counter. But here's an answer anyway:
const jsonToIterate = *'MyPreviousInputJson'*;
const names = {};
jsonToIterate.map(obj => {
if(obj.name in names){
names[obj.name]++
}
else{
names[obj.name] = 1;
}
})

Get specific object by id from array of objects in AngularJS

I have a JSON file containing some data I d like to access on my AngularJS website. Now what I want is to get only one object from the array. So I d like for example Item with id 1.
The data looks like this:
{ "results": [
{
"id": 1,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] }
I'd like to load the data with AngularJS $http functionality like this:
$http.get("data/SampleData.json");
which is working. But how can I now get a specific data object (by id) from the array I get from $http.get ?
Using ES6 solution
For those still reading this answer, if you are using ES6 the find method was added in arrays. So assuming the same collection, the solution'd be:
const foo = { "results": [
{
"id": 12,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] };
foo.results.find(item => item.id === 2)
I'd totally go for this solution now, as is less tied to angular or any other framework. Pure Javascript.
Angular solution (old solution)
I aimed to solve this problem by doing the following:
$filter('filter')(foo.results, {id: 1})[0];
A use case example:
app.controller('FooCtrl', ['$filter', function($filter) {
var foo = { "results": [
{
"id": 12,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] };
// We filter the array by id, the result is an array
// so we select the element 0
single_object = $filter('filter')(foo.results, function (d) {return d.id === 2;})[0];
// If you want to see the result, just check the log
console.log(single_object);
}]);
Plunker: http://plnkr.co/edit/5E7FYqNNqDuqFBlyDqRh?p=preview
For anyone looking at this old post, this is the easiest way to do it currently. It only requires an AngularJS $filter. Its like Willemoes answer, but shorter and easier to understand.
{
"results": [
{
"id": 1,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
]
}
var object_by_id = $filter('filter')(foo.results, {id: 2 })[0];
// Returns { id: 2, name: "Beispiel" }
WARNING
As #mpgn says, this doesn't work properly. This will catch more results. Example: when you search 3 this will catch 23 too
personally i use underscore for this kind of stuff... so
a = _.find(results,function(rw){ return rw.id == 2 });
then "a" would be the row that you wanted of your array where the id was equal to 2
I just want to add something to Willemoes answer.
The same code written directly inside the HTML will look like this:
{{(FooController.results | filter : {id: 1})[0].name }}
Assuming that "results" is a variable of your FooController and you want to display the "name" property of the filtered item.
You can use ng-repeat and pick data only if data matches what you are looking for using ng-show
for example:
<div ng-repeat="data in res.results" ng-show="data.id==1">
{{data.name}}
</div>
You can just loop over your array:
var doc = { /* your json */ };
function getById(arr, id) {
for (var d = 0, len = arr.length; d < len; d += 1) {
if (arr[d].id === id) {
return arr[d];
}
}
}
var doc_id_2 = getById(doc.results, 2);
If you don't want to write this messy loops, you can consider using underscore.js or Lo-Dash (example in the latter):
var doc_id_2 = _.filter(doc.results, {id: 2})[0]
If you want the list of items like city on the basis of state id then use
var state_Id = 5;
var items = ($filter('filter')(citylist, {stateId: state_Id }));
Unfortunately (unless I'm mistaken), I think you need to iterate over the results object.
for(var i = 0; i < results.length; i += 1){
var result = results[i];
if(result.id === id){
return result;
}
}
At least this way it will break out of the iteration as soon as it finds the correct matching id.
Why complicate the situation? this is simple write some function like this:
function findBySpecField(data, reqField, value, resField) {
var container = data;
for (var i = 0; i < container.length; i++) {
if (container[i][reqField] == value) {
return(container[i][resField]);
}
}
return '';
}
Use Case:
var data=[{
"id": 502100,
"name": "Bərdə filialı"
},
{
"id": 502122
"name": "10 saylı filialı"
},
{
"id": 503176
"name": "5 sayli filialı"
}]
console.log('Result is '+findBySpecField(data,'id','502100','name'));
output:
Result is Bərdə filialı
The only way to do this is to iterate over the array. Obviously if you are sure that the results are ordered by id you can do a binary search
$scope.olkes = [{'id':11, 'name':'---Zəhmət olmasa seçim edin---'},
{'id':15, 'name':'Türkyə'},
{'id':45, 'name':'Azərbaycan'},
{'id':60, 'name':'Rusya'},
{'id':64, 'name':'Gürcüstan'},
{'id':65, 'name':'Qazaxıstan'}];
<span>{{(olkes | filter: {id:45})[0].name}}</span>
output: Azərbaycan
If you can, design your JSON data structure by making use of the array indexes as IDs. You can even "normalize" your JSON arrays as long as you've no problem making use of the array indexes as "primary key" and "foreign key", something like RDBMS. As such, in future, you can even do something like this:
function getParentById(childID) {
var parentObject = parentArray[childArray[childID].parentID];
return parentObject;
}
This is the solution "By Design". For your case, simply:
var nameToFind = results[idToQuery - 1].name;
Of course, if your ID format is something like "XX-0001" of which its array index is 0, then you can either do some string manipulation to map the ID; or else nothing can be done about that except through the iteration approach.
I know I am too late to answer but it's always better to show up rather than not showing up at all :). ES6 way to get it:
$http.get("data/SampleData.json").then(response => {
let id = 'xyz';
let item = response.data.results.find(result => result.id === id);
console.log(item); //your desired item
});
The simple way to get (one) element from array by id:
The find() method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
function isBigEnough(element) {
return element >= 15;
}
var integers = [12, 5, 8, 130, 160, 44];
integers.find(isBigEnough); // 130 only one element - first
you don't need to use filter() and catch first element xx.filter()[0] like in comments above
The same for objects in array
var foo = {
"results" : [{
"id" : 1,
"name" : "Test"
}, {
"id" : 2,
"name" : "Beispiel"
}, {
"id" : 3,
"name" : "Sample"
}
]};
var secondElement = foo.results.find(function(item){
return item.id == 2;
});
var json = JSON.stringify(secondElement);
console.log(json);
Of course if you have multiple id then use filter() method to get all objects.
Cheers
function isBigEnough(element) {
return element >= 15;
}
var integers = [12, 5, 8, 130, 160, 44];
integers.find(isBigEnough); // 130 only one element - first
var foo = {
"results" : [{
"id" : 1,
"name" : "Test"
}, {
"id" : 2,
"name" : "Beispiel"
}, {
"id" : 3,
"name" : "Sample"
}
]};
var secondElement = foo.results.find(function(item){
return item.id == 2;
});
var json = JSON.stringify(secondElement);
console.log(json);
projectDetailsController.controller('ProjectDetailsCtrl', function ($scope, $routeParams, $http) {
$http.get('data/projects.json').success(function(data) {
$scope.projects = data;
console.log(data);
for(var i = 0; i < data.length; i++) {
$scope.project = data[i];
if($scope.project.name === $routeParams.projectName) {
console.log('project-details',$scope.project);
return $scope.project;
}
}
});
});
Not sure if it's really good, but this was helpful for me..
I needed to use $scope to make it work properly.
use $timeout and run a function to search in "results" array
app.controller("Search", function ($scope, $timeout) {
var foo = { "results": [
{
"id": 12,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] };
$timeout(function () {
for (var i = 0; i < foo.results.length; i++) {
if (foo.results[i].id=== 2) {
$scope.name = foo.results[i].name;
}
}
}, 10);
});
I would iterate over the results array using an angularjs filter like this:
var foundResultObject = getObjectFromResultsList(results, 1);
function getObjectFromResultsList(results, resultIdToRetrieve) {
return $filter('filter')(results, { id: resultIdToRetrieve }, true)[0];
}

Categories

Resources