Related
I have restaurant data array , I should make another array by grouping items by category that belongs to , I should convert this array :
[
{
"category": {
"title": "Appetizers",
},
"id": 1,
"price": "10",
"title": "Spinach Artichoke Dip",
},
{
"category": {
"title": "Appetizers",
},
"id": 2,
"price": "10",
"title": "Hummus",
},
{
"category": {
"title": "Salads",
},
"id": 3,
"price": "7",
"title": "Greek",
},
{
"category": {
"title": "Salads",
},
"id": 4,
"price": "9",
"title": "Beyn",
}
]
into a new array that should be as final result like this:
[{
"category": "Appetizers",
"items" : ["Spinach Artichoke Dip","Hummus"]
},
{
"category" : "Salads",
"items" :["Greek", "Beyn"]
}
]
I can't find how to do it could you please help
Lets say that your data is a constant called data
So you can do this:
const data = [
{
"category": {
"title": "Appetizers",
},
"id": 1,
"price": "10",
"title": "Spinach Artichoke Dip",
},
{
"category": {
"title": "Appetizers",
},
"id": 2,
"price": "10",
"title": "Hummus",
},
{
"category": {
"title": "Salads",
},
"id": 3,
"price": "7",
"title": "Greek",
},
{
"category": {
"title": "Salads",
},
"id": 4,
"price": "9",
"title": "Beyn",
}
];
const result = [];
data.forEach((item) => {
const category = item.category.title;
const title = item.title;
let foundCategory = result.find((c) => c.category === category);
if (foundCategory) {
foundCategory.items.push(title);
} else {
result.push({ category, items: [title] });
}
});
console.log(result);
Now your desired result will be stored in result
happy coding
const itemsToCategories = (itemsArr) => {
const store = {};
itemsArr.forEach(item => {
const categoryTitle = item.category.title;
if (!store[categoryTitle]) store[categoryTitle] = [];
store[categoryTitle].push(item.title);
});
return Object.entries(store).map(([category, items]) => ({ category, items}));
};
This solution should be a bit faster than the accepted answer for large data sets. The main difference is the use of an object (store) instead of an array, so lookups by the category title are more efficient. Then we build an array from that object at the end.
This does have more overhead than the accepted solution above, so for smaller data sets, this ends up being slower in comparison.
i have prepared a json tree from a plain json. But i need to sort the tree with multiple conditions.
for example at level 1 we have multiple objects. we need to sort with level and then with a name property.
level is a number and name is an alphanumeric. so name sorting is alphabets first and then numbers
Below is the input json
var inputJson = [
{
"level": "1",
"leafFlag": "1",
"path":"p123",
"name":"food23"
},
{
"level": "1",
"leafFlag": "1",
"path":"r125",
"name":"car1"
},
{
"level": "2",
"leafFlag": "0",
"path":"p123/p345",
"name":"apple345"
},
{
"level": "2",
"leafFlag": "1",
"path":"p123/p095",
"name":"123banana"
},
{
"level": "3",
"leafFlag": "0",
"path":"p123/p095/p546",
"name":"543"
},
{
"level": "2",
"leafFlag": "1",
"path":"r125/yhes",
"name":"tata78"
}
]
var output = [];
The below code prepares the json tree.
I tried here for sorting with multiple properties
inputJson = inputJson.sort((a, b) => (parseInt(a.level) > parseInt(b.level)) ? 1 : -1)
inputJson.forEach(v => {
if (v.level == "1") {
v.children = [];
output.push(v);
}
else {
pathValues = v.path.split("/");
pathValues.pop();
var node = null;
var fullPath = "";
pathValues.forEach(p => {
fullPath = fullPath === "" ? p : fullPath + "/" + p;
node = (node == null ? output : node.children).find(o => o.path === fullPath);
})
node.children = node.children || [];
node.children.push(v);
}
})
Output from above:
var output = [
{
"level": "1",
"leafFlag": "1",
"path": "p123",
"name": "food23",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "p123/p345",
"name": "apple"
},
{
"level": "2",
"leafFlag": "1",
"path": "p123/p095",
"name": "banana",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "p123/p095/p546",
"name": "grapes"
}
]
}
]
},
{
"level": "1",
"leafFlag": "1",
"path": "r125",
"name": "car",
"children": [
{
"level": "2",
"leafFlag": "1",
"path": "r125/yhes",
"name": "tata",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "r125/yhes/sdie",
"name": "Range Rover"
}
]
},
{
"level": "2",
"leafFlag": "0",
"path": "r125/theys",
"name": "suzuki"
}
]
}
]
Expected output:
[
{
"level": "1",
"leafFlag": "1",
"path": "r125",
"name": "car",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "r125/theys",
"name": "suzuki"
},
{
"level": "2",
"leafFlag": "1",
"path": "r125/yhes",
"name": "tata",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "r125/yhes/sdie",
"name": "Range Rover"
}
]
}
]
},
{
"level": "1",
"leafFlag": "1",
"path": "p123",
"name": "food",
"children": [
{
"level": "2",
"leafFlag": "0",
"path": "p123/p345",
"name": "apple"
},
{
"level": "2",
"leafFlag": "1",
"path": "p123/p095",
"name": "banana",
"children": [
{
"level": "3",
"leafFlag": "0",
"path": "p123/p095/p546",
"name": "grapes"
}
]
}
]
}
]
I tried something like below
inputJson = inputJson.sort((a, b) => (parseInt(a.level) > parseInt(b.level)) ? 1 : -1 && a.name > b.name ? 1 ? -1)
You could take a single sort by sorting levels first and then by name.
.sort((a, b) => a.level - b.level || a.name.localeCompare(b.name))
Then build the tree with the sorted items.
var data = [{ level: "1", leafFlag: "1", path: "p123", name: "food" }, { level: "1", leafFlag: "1", path: "r125", name: "car" }, { level: "2", leafFlag: "0", path: "p123/p345", name: "apple" }, { level: "2", leafFlag: "1", path: "p123/p095", name: "banana" }, { level: "3", leafFlag: "0", path: "p123/p095/p546", name: "grapes" }, { level: "2", leafFlag: "1", path: "r125/yhes", name: "tata" }],
result = data
.sort((a, b) => a.level - b.level || a.name.localeCompare(b.name))
.reduce((r, o) => {
let p = o.path.split('/');
p.pop();
let target = p.reduce((t, _, i, p) => {
var path = p.slice(0, i + 1).join('/'),
temp = (t.children = t.children || []).find(q => q.path === path);
if (!temp) t.children.push(temp = { path }); // this is not necessary
// if all nodes are given
return temp;
}, { children: r });
(target.children = target.children || []).push({ ...o });
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var rootes= inputJson.filter(x=>x.level=='1')
for(i=0;i<rootes.length;i++){
rootes[i].children=[] }
var objwithchild = inputJson.filter(x=>x.leafFlag=='1')
for(i=0;i<objwithchild.length;i++){
objwithchild[i].children=[] }
inputJson.forEach(x=>{
patharr=x.path.split('/')
path=patharr.pop()
switch (x.level) {
case '2':
rootes.filter(p=>{if(p.path==patharr[0]){p.children.push(x)}
})
break
case '3':
objwithchild.filter(p=>{if(p.path==patharr[0]+'/'+patharr[1]){p.children.push(x)}
})
break
}
})
console.dir(rootes,{depth:null})
You should first sort by name, then re-sort the sorted array by level.
inputJson = inputJson.sort((a,b) => {return a.name > b.name}).sort((a,b) => {return (Number(a.level) - Number(b.level)};
I have below dynamic nested JSON object arrays and I wanted to get the desired output with JavaScript grouped by id from both.
First Array:
[
{
"id": "11",
"name": "emp1",
"location": [
{ "name": "abc", "id": "lc1" }
]
},
{
"id": "11",
"name": "emp2",
"location": [
{ "name": "abc", "id": "lc1" },
]
},
{
"id": "22",
"name": "emp3",
"location": [
{ "name": "xyz", "id": "lc2" }
]
}
]
Second array like below.
[
{
"name": "sub1",
"id": "11"
...
},
{
"name": "sub1.1",
"id": "11"
...
},
{
"name": "sub2",
"id": "22"
...
}
]
Desired Output:
[
{
"id": "11",
"first": [{"name": "emp1"},
{"name": "emp2"}],
"second": [{"name": "sub1"},{"name": "sub1.1"}],
"location": [{"name": "abc"}]
},
{
"id": "22",
"first": [{"name": "emp3"}],
"second": [{"name": "sub2"}],
"location": [{"name": "xyz"}]
}
]
How to get the desired output like above using javascript/angularjs?
I would do it using the amazing Array#reduce function.
Note that I have named your first array as a1, second as a2 and result as res.
a1.reduce(function(arr, obj) {
var existing = arr.filter(function(res) {
return res.id === obj.id
})[0]
if (existing) {
existing.first.push({
name: obj.name
})
} else {
var second = a2.filter(function(res) {
return res.id === obj.id
})
var secondObj = second.length ? second.map(function(sec) {
return {
name: sec.name
};
}) : []
arr.push({
id: obj.id,
first: [{
name: obj.name
}],
second: secondObj,
location: obj.location
})
}
return arr;
}, [])
Here's the working snippet. Take a look!
var a1 = [{
"id": "11",
"name": "emp1",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "11",
"name": "emp2",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "22",
"name": "emp3",
"location": [{
"name": "xyz",
"id": "lc2"
}]
}
]
var a2 = [{
"name": "sub1",
"id": "11"
}, {
"name": "sub1.1",
"id": "11"
},
{
"name": "sub2",
"id": "22"
}
]
var res = a1.reduce(function(arr, obj) {
var existing = arr.filter(function(res) {
return res.id === obj.id
})[0]
if (existing) {
existing.first.push({
name: obj.name
})
} else {
var second = a2.filter(function(res) {
return res.id === obj.id
})
var secondObj = second.length ? second.map(function(sec) {
return {
name: sec.name
};
}) : []
arr.push({
id: obj.id,
first: [{
name: obj.name
}],
second: secondObj,
location: obj.location
})
}
return arr;
}, [])
console.log(res)
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
var red1 = [{
"id": "11",
"name": "emp1",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "11",
"name": "emp2",
"location": [{
"name": "abc",
"id": "lc1"
}]
},
{
"id": "22",
"name": "emp3",
"location": [{
"name": "xyz",
"id": "lc2"
}]
}
]
var b = [{
"name": "sub1",
"id": "11"
},
{
"name": "sub2",
"id": "22"
}
]
var identication = {}
var result = []
red1.forEach(function(val) {
if (val['id'] in identication) {
var t = {}
t['name'] = val['name']
result[identication[val['id']]]['first'].push(t)
} else {
var t = {}
t['name'] = val['name']
val['first'] = []
val['first'].push(t)
delete val['name']
var identity = result.push(val)
identication[val['id']] = identity - 1;
}
})
b.forEach(function(d) {
if (d['id'] in identication) {
var t = {
'name': d['name']
}
if (!('second' in result[identication[d['id']]])) {
result[identication[d['id']]]['second'] = []
}
result[identication[d['id']]]['second'].push(t)
} else {
var t = {}
for (key in d) {
if (key == 'name')
continue
t[key] = d[key]
}
t['second'] = [{
'name': d['name']
}]
var identity = result.push(t)
identication[d['id']] = identity - 1;
}
})
console.log(result)
In javascript/jquery how do i achieve following
old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
Using jquery iterate over the above and change to following
new_dataset = [
{
"dob":"xyz",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
},{
"dob":"er",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
}]
If someone can give the code to transform the data it would help me to understand the iteration
You could do something like:
function transformDataset(oldDataset) {
var newDataset = [];
var newObj;
for (var i = 0; i < oldDataset.length; i++) {
newObj = transformObj(oldDataset[i]);
newDataset.push(newObj);
}
return newDataset;
}
function transformObj(obj) {
var children = obj.children;
obj.name = obj.name.first + ' ' + obj.name.last;
obj.start_date = obj.start_date.month + ' ' + obj.start_date.day + ' ' + obj.start_date.year;
obj.children = [];
for (var i = 0; i < children.length; i++) {
obj.children.push(children[i].child.id);
}
return obj;
}
var new_dataset = transformDataset(old_dataset);
Note that new_dataset will have an array of child id instead of an object with multiple child_id properties.
You also had a typo in old_dataset.start_date.month (was written moth)(or maybe that was intentional).
use map first to iterate the array data (old_dataset), replace element name & start_date with new value then return the array
const old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
let new_dataset = old_dataset.map((arr) => {
arr.name = `${arr.name.first} ${arr.name.last}`
arr.start_date = `${arr.start_date.moth} ${arr.start_date.day} ${arr.start_date.year}`
return arr
})
console.log(new_dataset)
I'm planning on using materialized paths in MongoDB to represent a tree and need to convert the materialized paths back into a JSON tree.
ex.
// Materialized path
var input = [
{"id": "0", "path": "javascript" },
{"id": "1", "path": "javascript/database" },
{"id": "2", "path": "javascript/database/tree" },
{"id": "3", "path": "javascript/mvc" },
{"id": "4", "path": "javascript/mvc/knockout.js"},
{"id": "5", "path": "javascript/mvc/backbone.js"},
{"id": "6", "path": "c++" },
{"id": "7", "path": "c++/c0xx"},
{"id": "8", "path": "c++/c0xx/lambda expressions"},
{"id": "9", "path": "c++/c0xx/vc10" }
];
The result would be:
[
{
"id": "0",
"name": "javascript",
"children": [
{
"id": "1",
"name": "database",
"children": [
{
"id": "2",
"name": "tree",
"children": []
}
]
},
{
"id": "3",
"name": "mvc",
"children": [
{
"id": "4",
"name": "knockout.js",
"children": []
},
{
"id": "5",
"name": "backbone.js",
"children": []
}
]
}
]
},
{
"id": "6",
"name": "c++",
"children": [
{
"id": "7",
"name": "c0xx",
"children": [
{
"id": "8",
"name": "lambda expressions",
"children": []
},
{
"id": "9",
"name": "vc10",
"children": []
}
]
}
]
}
]
I found Convert delimited string into hierarchical JSON with JQuery which works fine.
And I also found Build tree from materialized path which is written in Ruby and uses recursion. I'm interested and curious to see this implemented in Javascript and wonder whether there are any folks that are fluent in both Ruby and Javascript who would like to rewrite it. I did try a Ruby to JS converter, but the result was incomprehensible.
Thanks,
Neville
var Comment = new Schema({
date : {
type : Date,
default : Date.now
},
event: ObjectId,
body : String,
pathComment : String,
user: Array
})
Comment.virtual('level').get(function() {
return this.pathComment.split(',').length;
});
Comment.find({event: event.id}).sort({pathComment:1}).exec(function(err, comment){
var collectComment = function(comment){
return {
body: comment.body,
event: comment.event,
pathComment: comment.pathComment,
id: comment._id,
level: comment.level,
user: comment.user[0],
date: comment.date,
comments: []
};
}
var tplComment = [];
var createChildComment = function(comment, currentNode, level){
if(level==1){
comment.push(collectComment(currentNode));
}else{
createChildComment(comment[comment.length-1]['comments'], currentNode,level-1);
}
return;
}
for(var k in comment){
createChildComment(tplComment, comment[k],comment[k].level);
}
});