Node.js - How to merge objects inside an array based on condition? - javascript

In Node.js, I have 3 sets of data like
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"dailyData":159392.235451,
"dailyDataInUSC":255.284807
}
]
and
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"monthlyData":159392.235451,
"monthlyDataInUSC":255.284807
},
{
"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
"monthlyData":349392.455451,
"monthlyDataInUSC":655.234807
}
]
and
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"threeMonthsData":159392.235451,
"threeMonthsDataInUSC":255.284807
},
{
"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
"threeMonthsData":349392.455451,
"threeMonthsDataInUSC":655.234807
},
{
"userId":"34sdf34-67j4-54nd-6763-d2ec81e8aaf3",
"threeMonthsData":6789392.455451,
"threeMonthsDataInUSC":905.655807
}
]
How can I combine this to one object based on userId(filter) inside an array.
Eg, output should be like
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"dailyData":159392.235451,
"dailyDataInUSC":255.284807,
"monthlyData":159392.235451,
"monthlyDataInUSC":255.284807,
"threeMonthsData":159392.235451,
"threeMonthsDataInUSC":255.284807
}
]
Please help me to achieve this.

A combination of spread, reduce and findIndex can be used to solve the problem.
Combine the original arrays into a single array using the spread operator.
Use reduce to group the elements by key (in this case userId)
Something like this :
const dailyData = [{"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3","dailyData":159392.235451,"dailyDataInUSC":255.284807}];
const monthlyData = [{"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3","monthlyData":159392.235451,"monthlyDataInUSC":255.284807}, {"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3","monthlyData":349392.455451,"monthlyDataInUSC":655.234807}]
const triMonthlyData = [{"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3","threeMonthsData":159392.235451,"threeMonthsDataInUSC":255.284807}, {"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3","threeMonthsData":349392.455451,"threeMonthsDataInUSC":655.234807}, {"userId":"34sdf34-67j4-54nd-6763-d2ec81e8aaf3","threeMonthsData":6789392.455451,"threeMonthsDataInUSC":905.655807}]
const combinedData = [...dailyData, ...monthlyData, ...triMonthlyData].reduce((mergedResult, curElement) => {
let matchingElementIdx = mergedResult.findIndex(ele => ele.userId === curElement.userId);
if (matchingElementIdx !== -1) {
mergedResult[matchingElementIdx] = {...mergedResult[matchingElementIdx], ...curElement};
} else {
mergedResult = [...mergedResult, curElement];
}
return mergedResult;
}, []);
console.log(combinedData);

const aa = () => {
let aa = [
{
userId: "54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
dailyData: 159392.235451,
dailyDataInUSC: 255.284807
}
];
let bb = [
{
userId: "54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
monthlyData: 159392.235451,
monthlyDataInUSC: 255.284807
},
{
userId: "23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
monthlyData: 349392.455451,
monthlyDataInUSC: 655.234807
}
];
let cc = [
{
userId: "54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
threeMonthsData: 159392.235451,
threeMonthsDataInUSC: 255.284807
},
{
userId: "23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
threeMonthsData: 349392.455451,
threeMonthsDataInUSC: 655.234807
},
{
userId: "34sdf34-67j4-54nd-6763-d2ec81e8aaf3",
threeMonthsData: 6789392.455451,
threeMonthsDataInUSC: 905.655807
}
];
let newArrObj = aa;
bb.forEach(item => {
let index = newArrObj.findIndex(item1 => item1.userId === item.userId);
if (index === -1) {
newArrObj = [...newArrObj, item];
} else {
newArrObj[index] = { ...newArrObj[index], ...item };
}
});
cc.forEach(item => {
let index = newArrObj.findIndex(item1 => item1.userId === item.userId);
if (index === -1) {
newArrObj = [...newArrObj, item];
} else {
newArrObj[index] = { ...newArrObj[index], ...item };
}
});
console.log(newArrObj);
};

Related

How to replace the keys "names" in javascript

Below is the object
{
'File_12345.ZLM': {
MeterID_12345: {
BASIC_INFO: [Object]
}
}
}
{
'File_678910.ZLM': {
MeterID_678910: {
BASIC_INFO: [Object],
}
}
}
===============================================================================================
I want File_12345.ZLM and File_678910.ZLM replaced with key name as "FileName" and
MeterID_12345 and MeterID_678910 replaced with "MeterId"
So Expected Output would be as below
{
'FileName': {
MeterId: {
BASIC_INFO: [Object]
}
}
}
{
'FileName': {
MeterId: {
BASIC_INFO: [Object],
}
}
}
As #efkah pointed out, the RegEx solution here:
const files = [{'File_12345.ZLM':{MeterID_12345:{BASIC_INFO:[]}}},{'File_678910.ZLM':{MeterID_678910:{BASIC_INFO:[]}}}];
const renamed = JSON.stringify(files)
.replaceAll(/File_\d+\.ZLM/g, 'FileName')
.replaceAll(/MeterID_\d+/g, 'MeterId');
const result = JSON.parse(renamed);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0 }
The idea is to grab the keys of the objects, since there is only one. With that we get to know the key we want to replace. Do it for both keys and voilà!
I've added a second way to do it, to flatten the objects a bit to make them easier to use, and to also not loose the filename and meterid info.
const files = [{
'File_12345.ZLM': {
MeterID_12345: {
BASIC_INFO: []
}
}
},
{
'File_678910.ZLM': {
MeterID_678910: {
BASIC_INFO: [],
}
}
}];
console.log(files.map(f=>{
const filename = Object.keys(f)[0];
f.FileName = f[filename]; delete f[filename];
const MeterId = Object.keys(f.FileName)[0];
f.FileName.MeterId = f.FileName[MeterId]; delete f.FileName[MeterId];
return f;
}));
const files2 = [{
'File_12345.ZLM': {
MeterID_12345: {
BASIC_INFO: []
}
}
},
{
'File_678910.ZLM': {
MeterID_678910: {
BASIC_INFO: [],
}
}
}];
console.log(files2.map(f=>{
const filename = Object.keys(f)[0];
const MeterId = Object.keys(f[filename])[0];
return {FileName:filename,MeterId,BASIC_INFO:f[filename][MeterId].BASIC_INFO};
}));
const data = [{
'File_12345.ZLM':{
MeterID_12345: {
BASIC_INFO: []
}
}
},{ 'File_678910.ZLM': { MeterID_678910: { BASIC_INFO: [], } } }]
const obj = data.map(item => {
const Meterkeys = Object.keys(item)
const Meterkey = Meterkeys.find(k => k.includes('File'))
if (Meterkey) {
const Filekeys = Object.keys(item[Meterkey])
const Filekey = Filekeys.find(k => k.includes('Meter'))
const res = {
...item,
FileName: {
...item[Meterkey],
MeterId: (item[Meterkey])[Filekey]
}
}
delete res[Meterkey]
delete res.FileName[Filekey]
return res;
} else {
return item
}
})
console.log(obj)
const obj = {oldKey: 'value'};
obj['newKey'] = obj['oldKey'];
delete obj['oldKey'];
console.log(obj); // 👉️ {newKey: 'value'}

remove 2 common array item javascript

I have 2 arrays
let arryOne =
[
{
'catRefId' : "200531-2"
},
{
'catRefId' : "201425-1"
},
{
'catRefId' : "201423-1"
},
]
let arryTwo =
[
{
'removeId' : "200531-2"
},
{
'removeId' : "201425-1"
},
]
I tried below code but not working
let _finalArray = [];
for (let index = 0; index < arryOne.length; index++) {
_finalArray = arryOne.filter(obj => obj.catRefId === arryTwo[index].removeId)
}
Here's an approach using Set
let arryTwo = [{ removeId: '200531-2' }, { removeId: '201425-1'}];
let arryOne = [{ catRefId: '200531-2' }, { catRefId: '201425-1'},{ catRefId: '201423-1' }];
const idsToRemove = new Set(arryTwo.map(({ removeId }) => removeId));
const _finalArray = arryOne.filter((item) => !idsToRemove.has(item.catRefId));
console.log(_finalArray);
This is a possible solution:
First we extract the Ids from the second array.
Then we filter all matching references.
What's left is all references not present in arryTwo.
let _finalArray = [];
_finalArray = arryOne.filter(obj => !arryTwo.map(obj => obj.removeId).includes(obj.catRefId));

I want to turn a JavaScript array into a nested object form

I want to convert an array with this shape into a nested object shape.
I've been thinking about it for hours, but I can't come up with a proper way. Any good way?
before
let files2 = [
"folder/empty_file.txt",
"folder/inner file.txt",
"user16.txt",
"reagjjjd.md",
"folder/folder2/hi.txt",
];
after
let files = [
{ folder: [{ folder2: ["hihi.txt"] }, "empty_file.txt", "inner file.txt"] },
"user16.txt",
"reagjjjd.md",
];
I would appreciate any help or guidance here. Thanks!
Here is a solution that can convert arbitrary folder depth into a tree according to your requirement. It basically builds the tree through text splitting and recursion, which works but is likely not ideal. I wish it were a little simpler, but hopefully it helps if no-one else offers a better solution.
// const path = require("path");
// const sep = path.sep;
const sep = "/";
const input = [
"folder/empty_file.txt",
"folder/inner file.txt",
"user16.txt",
"reagjjjd.md",
"folder/folder2/hi.txt",
];
const get_files = (list) => {
return list.filter((s) => s.length < 2).map((s) => s[0]);
};
const get_folder_names = (list) => {
return [...new Set(list.filter((s) => s.length > 1).map((s) => s[0]))];
};
const get_folder_contents = (list, folder) => {
return list
.filter((s) => s.length > 1)
.filter((s) => s[0] == folder)
.map((s) => s.slice(1));
};
const get_folders = (list) => {
return get_folder_names(list).map((folder) => {
return { [folder]: build_tree(get_folder_contents(list, folder)) };
});
};
function build_tree(list) {
const tree = [];
tree.push(...get_files(list));
tree.push(...get_folders(list));
return tree;
}
const list = input.map((s) => s.split(sep));
const output = build_tree(list);
console.log("Tree:", JSON.stringify(output));
newArr by your structure .
newArr1 by my structure suggest
let files = [
"folder/empty_file.txt",
"folder/inner file.txt",
"user16.txt",
"reagjjjd.md",
"folder/folder2/hi.txt",
]
let newArr = files.reduce((res, path) => {
let convertArr = path.split("/")
if(convertArr.length < 2) return [...res, path]
let parent = res
let treePath = convertArr.forEach( (ele, key) => {
let temParent = parent.find(el => typeof el === 'object' && el.hasOwnProperty(ele))
if (temParent) {
parent = temParent[ele]
} else {
let tmp = key === convertArr.length-1 ? ele : {[ele] : []}
parent.push(tmp)
parent = tmp[ele]
}
})
return res
}, [])
let files2 = [
"folder/empty_file.txt",
"folder/inner file.txt",
"user16.txt",
"reagjjjd.md",
"folder/folder2/hi.txt",
]
let newArr1 = files2.reduce((res, path) => {
let convertArr = path.split("/")
let parent = res
let treePath = convertArr.forEach( ele => {
let temParent = parent.find(el => el.path === ele)
if (!temParent) {
let tmp = {path: ele, children: []}
parent.push(tmp)
parent = tmp.children
} else {
parent = temParent.children
}
})
return res
}, [])
console.log(newArr)
console.log(newArr1)
I think the array structure should follow this format for ease of use :
[
{
path : 'folder',
children : [
{
path : 'empty_file.txt',
children : []
},
{
path : 'inner file.txt',
children : []
},
{
path : 'folder2',
children : [
{
path : 'hi.txt',
children : []
}
]
},
]
},
{
path : 'user16.txt',
children : []
},
{
path : 'reagjjjd.md',
children : []
}
]

Put object in nested object

Ik have to object and I want to combine those together the right way. I use this code to get them together:
return { record, voorraad: resultsr.filter(x => x != null) }
the output of this will be
{
record:{
_id:"5e8c226e62e43e41b59fe3d3",
naam:"Dames fietsen"
},
voorraad:[
{
_id:"5e8cc9e059fcf75489ebac84",
categorie:"5e8c226e62e43e41b59fe3d3",
status:1
}
]
}
But I like to have it this way
{
record:{
_id:"5e8c226e62e43e41b59fe3d3",
naam:"Dames fietsen",
voorraad:[
{
_id:"5e8cc9e059fcf75489ebac84",
categorie:"5e8c226e62e43e41b59fe3d3",
status:1
}
]
}
}
Who can help me?
this way ?
var data = {
"record":{
"_id":"5e8c226e62e43e41b59fe3d3",
"naam":"Dames fietsen"
},
"voorraad":[
{
"_id":"5e8cc9e059fcf75489ebac84",
"categorie":"5e8c226e62e43e41b59fe3d3",
"status":1
}
]
}
data.record.voorraad = data.voorraad
delete data.voorraad
console.log( JSON.stringify( data, 0 ,2))
uses destructuring:
const data = {
record:{
_id:"5e8c226e62e43e41b59fe3d3",
naam:"Dames fietsen"
},
voorraad:[
{
_id:"5e8cc9e059fcf75489ebac84",
categorie:"5e8c226e62e43e41b59fe3d3",
status:1
}
]
};
const { record, voorraad } = data;
const test = { ...record, voorraad: voorraad.filter(x => x != null) }
console.log(test);
// you have these
const record = {"_id":"5e8c226e62e43e41b59fe3d3", "naam":"Dames fietsen"};
const results = [
{
"_id":"5e8cc9e059fcf75489ebac84",
"categorie":"5e8c226e62e43e41b59fe3d3",
"status":1
}
];
// so just do this
record.voorraad = results.filter(x => x);
const returnValue = { record };
// and returnValue is what you want
console.log(returnValue);

Reformatting array of arrays to nested json in Javascript [duplicate]

I have an array like
[
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1",
.
.
.
]
Wherein my first string before | is the parent and the second string before | is the child and the third string after the second | is the subchild
How can I convert this array into an object like
[
{
"id": "parent1",
"children":[
{
"id": "child1",
"children":[
{
"id": "subChild1"
}
]
}
]
}
]
Parent -> child -> subchild object
Based on Sebastian's answer I tried below using typescript
private genTree(row) {
let self = this;
if (!row) {
return;
}
const [parent, ...children] = row.split('|');
if (!children || children.length === 0) {
return [{
id: parent,
children: []
}];
}
return [{
id: parent,
children: self.genTree(children.join('|'))
}];
}
private mergeDeep(children) {
let self = this;
const res = children.reduce((result, curr) => {
const entry = curr;
const existing = result.find((e) => e.id === entry.id);
if (existing) {
existing.children = [].concat(existing.children, entry.children);
} else {
result.push(entry);
}
return result;
}, []);
for (let i = 0; i < res.length; i++) {
const entry = res[i];
if (entry.children && entry.children.length > 0) {
entry.children = self.mergeDeep(entry.children);
}
};
return res;
}
private constructTree(statKeyNames){
let self = this;
const res = this.mergeDeep(statKeyNames.map(self.genTree).map(([e]) => e));
console.log(res);
}
but this gives me:
Cannot read property 'genTree' of undefined" error
Update:
As per Sebastian's comment changed self.genTree to this.genTree.bind(this) and it worked without any issues
You could use a mapper object which maps each object to it's unique path (You could map the object with each id, but id is not unique here). Then reduce each partial item in the array. Set the root object as the initialValue. The accumulator will be the parent object for the current item. Return the current object in each iteration.
const input = [
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent1|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1"
],
mapper = {},
root = { children: [] }
for (const str of input) {
let splits = str.split('|'),
path = '';
splits.reduce((parent, id, i) => {
path += `${id}|`;
if (!mapper[path]) {
const o = { id };
mapper[path] = o; // set the new object with unique path
parent.children = parent.children || [];
parent.children.push(o)
}
return mapper[path];
}, root)
}
console.log(root.children)
You have to use recursion for that. Take a look here:
const arr = [
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1"
];
function genTree(row) {
const [parent, ...children] = row.split('|');
if (!children || children.length === 0) {
return [{
id: parent,
children: []
}];
}
return [{
id: parent,
children: genTree(children.join('|'))
}];
};
function mergeDeep(children) {
const res = children.reduce((result, curr) => {
const entry = curr;
const existing = result.find((e) => e.id === entry.id);
if (existing) {
existing.children = [].concat(existing.children, entry.children);
} else {
result.push(entry);
}
return result;
}, []);
for (let i = 0; i < res.length; i++) {
const entry = res[i];
if (entry.children && entry.children.length > 0) {
entry.children = mergeDeep(entry.children);
}
};
return res;
}
const res = mergeDeep(arr.map(genTree).map(([e]) => e));
console.log(JSON.stringify(res, false, 2));
I used two helpers here: genTree(row) which recursively generates a simple tree from each row, and mergeDeep(children) which reduces the first-level trees in the result of arr.map(genTree).map(([e]) => e), and then iterates over the array and recursively does the same thing to all children of each entry.

Categories

Resources