javascript group a nested array of objects by child object value - javascript

Im trying to group an array of objects by a value of one of the child objects.
Im kinda getting want I want using reduce, but it seems to be combining the group by value where the parent objects are common.
let name = [
{
issue: "89",
status: ["test", "prod", "dev"]
},
{
issue: "45",
status: ["dev"]
}
];
const groups = name.reduce((groups, item) => {
const group = groups[item.status] || [];
group.push(item);
groups[item.status] = group;
return groups;
}, {});
console.log(JSON. stringify(groups));
I get the below results
{
"test,prod,dev":[
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
],
"dev":[
{
"issue":"45",
"status":[
"dev"
]
}
]
}
What id like is for it the produce the below:
{
"prod":[
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
],
"test":[
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
],
"dev":[
{
"issue":"45",
"status":[
"dev"
]
},
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
]
}
Im not sure how to produce my desired results easily.
many thanks

You need to group your object based on the status. You can use array#reduce with array#forEach.
const names = [ { issue: "89", status: ["test", "prod", "dev"] }, { issue: "45", status: ["dev"] } ],
result = names.reduce((r, o) => {
o.status.forEach(name => {
r[name] ??= [];
r[name].push(JSON.parse(JSON.stringify(o)));
});
return r;
},{});
console.log(result);

const group = Object.assign({}, ...name.reduce((p, c) => [...p, ...c.status], [])
.filter((v, i , a) => a.indexOf(v) === i)
.map(item => ({ [item]: name.filter(old => old.status.includes(item)) })))

Related

Array of object into a nested object for every value in the array

Trying to turn an array of objects into a nested object. Is there a good method for this? and how do I make it depending on the array length?
Working but is not universal:
https://codesandbox.io/s/thirsty-roentgen-3mdcjv?file=/src/App.js
What I have:
sorting: [
{
"id": "HighestDegree",
"options": [
"HighSchool",
"Undergraduate",
"Bachelor",
"Master",
"Doctor"
]
},
{
"id": "gender",
"options": [
"male",
"female"
]
}
]
What I want:
value: {
"Region": "Oklahoma",
"HighestDegree": {
"HighSchool": {
"male": null,
"female":null
},
"Undergraduate":{
"male": null,
"female":null
}
//and so on...
}
}
The code beneath works but is hardcoded for only two different options. I want it to be able to nest the length of the array. So lets say another object was age it would be {"HighSchool":{male:{"<25":null,"25-35":null}}} etc..
function testSortingArray() {
let sorting = [
{
id: "HighestDegree",
options: ["HighSchool", "Undergraduate", "Bachelor", "Master", "Doctor"]
},
{
id: "gender",
options: ["male", "female"]
}
];
let GoalArray = {};
if (sorting.length > 0) {
sorting[0].options.map((firstArray) => {
let currObject = {};
sorting[1].options.map((secondOption) => {
currObject[secondOption] = null;
});
GoalArray[firstArray] = currObject;
});
}
return GoalArray;
}
console.log(testSortingArray());
You can do it with a recursive function.
The function below reduces every options array to an object, and then continues populating that object if there are rest elements left from the original sorting array.
const fn = ([{ options }, ...rest]) => options.reduce((a, v) => ({
...a,
[v]: rest.length ? fn(rest): null
}), {});
const result = fn(sorting);
Besides the reduce() method, the code above makes use of object and array destructuring and spread syntax.
Complete snippet:
const sorting = [{
"id": "HighestDegree",
"options": [
"HighSchool",
"Undergraduate",
"Bachelor",
"Master",
"Doctor"
]
}, {
"id": "gender",
"options": [
"male",
"female"
]
}, {
"id": "age",
"options": [
"<25",
"25-35"
]
}];
const fn = ([{ options }, ...rest]) => options.reduce((a, v) => ({
...a,
[v]: rest.length ? fn(rest): null
}), {});
const result = fn(sorting);
console.log(result);

How to optimize reducer function

I have this function
const joinCages = arr => {
return arr.reduce((acc, { jaulaId, comunaCode }) => {
if (!acc.hasOwnProperty(jaulaId)) acc[jaulaId] = []
acc[jaulaId].push(comunaCode)
return acc
}, {})
}
The output is this:
{
JAU0000001: [ '130109' ],
JAU0000029: [ '100102', '100103' ],
JAU0000017: [ '100304', '100305' ]
}
What it does:
Create an object that group the "Comuna Code" in the key "jaula ID" from an array of objects
Data array
[
{
indexId: 104834,
jaulaId: "JAU0000001",
distributionCenterId: "100",
comunaCode: "130109",
orderType: "Retorno",
regionCode: "13"
},
{
indexId: 104836,
jaulaId: "JAU0000029",
distributionCenterId: "100",
comunaCode: "100102",
orderType: "Retorno",
regionCode: "13"
},
{
indexId: 104837,
jaulaId: "JAU0000029",
distributionCenterId: "100",
comunaCode: "100103",
orderType: "Retorno",
regionCode: "13"
}
]
I want to upgrade that function without the if statement and removing the return...Return implicit you know?
The problem is that I am failing coding this and I dont know where or how can I do this.
Upgraded function
const joinCages2 = arr => {
return arr.reduce((acc, { jaulaId, comunaCode }) => ({
...acc,
[jaulaId]: [jaulaId] ? [jaulaId].push(comunaCode) : [comunaCode]
}), {})
}
Thank you in advance.

How to make a array from another array with grouping data based on id .?

I have an array object as follows,
const data = [
{
"order_id":"ORDCUTHIUJ",
"branch_code":"MVPA",
"total_amt":199500,
"product_details":[
{
"image":"CC252.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORHOGFD79L",
"branch_code":"PBVR",
"total_amt":325880,
"product_details":[
{
"image":"1617382086515.jpg",
"cate":"Mobile Accessories"
},
{
"image":"1617382322759.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC251.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORIYDJLYSJ",
"branch_code":"MVPA",
"total_amt":1549500,
"product_details":[
{
"image":"CC250.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC256.jpg",
"cate":"Mobile Accessories"
}
]
}
]
what I want to achieve is to build a new array based on this, but I want to group the data with the same branch code under one object.
Expected Output:
const newData =
[
{
MVPA: [
{
order_id: 'ORIYDJLYSJ',
(otherdetails)
},
{
order_id: 'ORDCUTHIUJ',
(otherdetails
}
]
},
PBVR: [
{
order_id: 'ORHOGFD79L',
(otherdetails)
}
]
can someone help me out on how to achieve this.? I want a general solution, bcoz this data could be longer than this when I get from DB.
You can do it with Array.reduce.
data.reduce((o, a) => (o[a.branch_code] = [ ...(o[a.branch_code] || []), a], o), {})
First create an object which collects data with branch_code.
const obj = data.reduce((map,obj)=>{
if(obj.branch_code in map){
map[obj.branch_code].push({...obj})
}
else{
map[obj.branch_code]=[{...obj}]
}
return map
},{})
This gives
{MVPA: Array(2), PBVR: Array(1)}
Then,map over the keys of the above object to create your required array.
const result = Object.keys(obj).map(key => ({[key]:
[...obj[key]]}))
console.log('result',result)
This gives
(2) [{…}, {…}]
0: {MVPA: Array(2)}
1: {PBVR: Array(1)}
const uniqueBranchCode = [...new Set(data.map(i => i.branch_code))] // Get unique branch_code
const newData = uniqueBranchCode
.map(order => data.filter(orderSpecific => orderSpecific.branch_code === order)) // Filter to group together by branch_code
.map(item => ({[item[0].branch_code]: item})) // Assign key and return elements
const data = [
{
"order_id":"ORDCUTHIUJ",
"branch_code":"MVPA",
"total_amt":199500,
"product_details":[
{
"image":"CC252.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORHOGFD79L",
"branch_code":"PBVR",
"total_amt":325880,
"product_details":[
{
"image":"1617382086515.jpg",
"cate":"Mobile Accessories"
},
{
"image":"1617382322759.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC251.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORIYDJLYSJ",
"branch_code":"MVPA",
"total_amt":1549500,
"product_details":[
{
"image":"CC250.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC256.jpg",
"cate":"Mobile Accessories"
}
]
}
]
const uniqueBranchCode = [...new Set(data.map(i => i.branch_code))]
const newData = uniqueBranchCode
.map(order => data.filter(orderSpecific => orderSpecific.branch_code === order))
.map(item => ({[item[0].branch_code]: item}))
console.log(newData)
You can try this way
const data =[{"order_id":"ORDCUTHIUJ","branch_code":"MVPA","total_amt":199500,"product_details":[{"image":"CC252.jpg","cate":"Mobile Accessories"}]},{"order_id":"ORHOGFD79L","branch_code":"PBVR","total_amt":325880,"product_details":[{"image":"1617382086515.jpg","cate":"Mobile Accessories"},{"image":"1617382322759.jpg","cate":"Mobile Accessories"},{"image":"CC251.jpg","cate":"Mobile Accessories"}]},{"order_id":"ORIYDJLYSJ","branch_code":"MVPA","total_amt":1549500,"product_details":[{"image":"CC250.jpg","cate":"Mobile Accessories"},{"image":"CC256.jpg","cate":"Mobile Accessories"}]}];
const result = data.reduce((acc, {order_id, branch_code, product_details}) => {
acc[branch_code] ??= {[branch_code]: []};
acc[branch_code][branch_code].push({order_id, product_details});
return acc;
}, {});
console.log(Object.values(result));
let obj = {}
function comp(x) {
const f1 = data.filter(function (i) {
return i.branch_code === x
})
return f1
}
for (let i = 0; i < data.length; i++) {
obj[`${data[i].branch_code}`] = comp(data[i].branch_code)
}
console.log(obj)

Map Json data by JavaScript

I have a Json data that I want to have in a different format.
My original json data is:
{
"info": {
"file1": {
"book1": {
"lines": {
"102:0": [
"102:0"
],
"105:4": [
"106:4"
],
"106:4": [
"107:1",
"108:1"
]
}
}
}
}
}
And I want to map it as following:
{
"name": "main",
"children": [
{
"name": "file1",
"children": [
{
"name": "book1",
"group": "1",
"lines": [
"102",
"102"
],
[
"105",
"106"
],
[
"106",
"107",
"108"
]
}
],
"group": 1,
}
],
"group": 0
}
But the number of books and number of files will be more. Here in the lines the 1st part (before the :) inside the "" is taken ("106:4" becomes "106"). The number from the key goes 1st and then the number(s) from the value goes and make a list (["106", "107", "108"]). The group information is new and it depends on parent-child information. 1st parent is group 0 and so on. The first name ("main") is also user defined.
I tried the following code so far:
function build(data) {
return Object.entries(data).reduce((r, [key, value], idx) => {
//const obj = {}
const obj = {
name: 'main',
children: [],
group: 0,
lines: []
}
if (key !== 'reduced control flow') {
obj.name = key;
obj.children = build(value)
if(!(key.includes(":")))
obj.group = idx + 1;
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
The group information is not generating correctly. I am trying to figure out that how to get the correct group information. I would really appreciate if you can help me to figure it out.
You could use reduce method and create recursive function to build the nested structure.
const data = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}}
function build(data) {
return Object.entries(data).reduce((r, [key, value]) => {
const obj = {}
if (key !== 'lines') {
obj.name = key;
obj.children = build(value)
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
I couldn't understand the logic behind group property, so you might need to add more info for that, but for the rest, you can try these 2 functions that recursively transform the object into what you are trying to get.
var a = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}};
var transform = function (o) {
return Object.keys(o)
.map((k) => {
return {"name": k, "children": (k === "lines" ? parseLines(o[k]) : transform(o[k])) }
}
)
}
var parseLines = function (lines) {
return Object.keys(lines)
.map(v => [v.split(':')[0], ...(lines[v].map(l => l.split(":")[0]))])
}
console.log(JSON.stringify(transform(a)[0], null, 2));

Lowdb count each string in an array of objects

I'm trying to count the number of string in an array of objects using lowdb.
Here is a sample of my objects:
{
"tags": [
"test",
"test2"
]
},
{
"tags": [
"test",
"test3"
]
}
I'd like to get this:
{
test: 2,
test2: 1,
test3: 1
}
I have successfully get this doing like this:
_.each(selectAll().value(), (bookmark) => {
if (bookmark.tags.length > 0) {
_.each(bookmark.tags, (bookmarksTags) => {
if (!(bookmarksTags in tags)) {
tags[bookmarksTags] = 0
}
tags[bookmarksTags]++
})
}
})
It works but... it's ugly and I don't like it. Do you know a better and proper Lodash's way to do this?
You can use reduce() and forEach() with plain javascript.
var data = [{"tags":["test","test2"]},{"tags":["test","test3"]}]
var result = data.reduce(function(r, e) {
return (e.tags.forEach(e => r[e] = (r[e] || 0) + 1)), r
}, {})
console.log(result)
One way using Lodash:
_.countBy(_.flatMap(arr,'tags'))
Where arr is the source array
var o = [{ "tags": [ "test", "test2" ]},{ "tags": [ "test", "test3" ]}];
console.log(_.countBy(_.flatMap(o,'tags')));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Categories