I have a problem with converting Json data , I get a list objects with different categories for each category there are two versions , So I need to modify the in a way to get list of objects where each object key is the category and its value is list of its corresponding versions and details.
data = [
{
"category1": {
"name": "category1",
"id": 1,
"last_sync_date": "None",
"version": "Version 1"
}
},
{
"category1": {
"name": "category1",
"id": 2,
"last_sync_date": "None",
"version": "Version 2"
}
},
{
"category2": {
"name": "category2",
"id": 1,
"last_sync_date": "None",
"version": "Version 1"
}
},
{
"category3": {
"name": "category3",
"id": 2,
"last_sync_date": "None",
"version": "Version 2"
}
},
]
To:
data = {
category1: [
{
id: "1",
name: "category1",
last_sync_date: "01/01/2022 10:45 AM",
version: "Version 1"
},
{
id: "2",
name: "category1",
last_sync_date: "01/01/2022 10:45 AM",
version: "Version 2"
},
],
category2:[
{
id: "3",
name: "category2",
last_sync_date: "01/01/2022 10:45 AM",
version: "Version 1"
},
],
category3:[
{
id: "4",
name: "category3",
last_sync_date: "01/01/2022 10:45 AM",
version: "Version 1"
},
],
}
Note: I was able to provide only one unit of data.
This is not JSON btw, this is just a JavaScript Array of objects that needs to be converted into another structure.
This can be done with any of the loop logics. I can show you one example with Array.reduce
Logic
Loop through data array using Array.reduce
Take each object and get the keys of each object.
Check whether this key exist in out accumulator object
If the key exist, push the Object to existing key, else create an empty array as the value for that key and push our object to the emty array just created.
const data = [
{
category1: { name: "category1", id: 1, last_sync_date: "None", version: "Version 1" },
},
{
category1: { name: "category1", id: 2, last_sync_date: "None", version: "Version 2" },
},
{
category2: { name: "category2", id: 1, last_sync_date: "None", version: "Version 1" },
},
{
category3: { name: "category3", id: 2, last_sync_date: "None", version: "Version 2" },
},
];
const output = data.reduce((acc, curr) => {
const keys = Object.keys(curr);
keys.forEach((key) => {
acc[key] = acc[key] || [];
acc[key].push(curr[key]);
});
return acc;
}, {});
console.log(output);
The following uses Array#reduce to enumerate the data. It pulls out the category and the object associated with each item. The objects are then added to a result object, keyed by category and grouped within arrays.
Does this do what you want?
const data = [{
"category1": {
"name": "category1",
"id": 1,
"last_sync_date": "None",
"version": "Version 1"
}
}, {
"category1": {
"name": "category1",
"id": 2,
"last_sync_date": "None",
"version": "Version 2"
}
}, {
"category2": {
"name": "category2",
"id": 1,
"last_sync_date": "None",
"version": "Version 1"
}
}, {
"category3": {
"name": "category3",
"id": 2,
"last_sync_date": "None",
"version": "Version 1"
}
}, ]
const group = (data) =>
data.reduce((acc, c) => {
const [[category, value]] = Object.entries(c)
acc[category]
? acc[category].push(value)
: acc[category] = [value]
return acc
}, {})
console.log(group(data))
This is not a JSON structure. Input is an array of objects. According to your description you just want to convert it to another structure.
Here is a sample solution of this problem.
// const data = [{}, {}...]; Input array of objects
const ans = {};
data.map(object => {
const keys = Object.keys(object);// to get keys of current object
const firstKey = keys[0];
const value = object[firstKey];
if (ans[firstKey] == undefined) {
ans[firstKey] = [value];
} else {
ans[firstKey].push(value);
}
})
console.log(ans);
Related
I have a array of object like this :
{
"data": [
{
"id": 1,
"from": "2022-08-01",
"to": "2022-08-05",
"description": "test 1",
"files": [
{
"id": 1,
"hospital_name": "hospital 11",
"hospital_id": 11,
"period_id": 1
},
{
"id": 2,
"hospital_name": "hospital 11",
"hospital_id": 11,
"period_id": 1
}
]
},
{
"id": 2,
"from": "2022-08-06",
"to": "2022-08-10",
"description": "test 2",
"files": [
{
"id": 3,
"hospital_name": "hospital 12",
"hospital_id": 12,
"period_id": 2
},
{
"id": 4,
"hospital_name": "hospital 12",
"hospital_id": 12,
"period_id": 2
}
]
}
]
}
I want to convert the array to be like this :
{
"data": [
{
"id": 1, // this is period id
"hospital_name": "hospital 11",
"hospital_id": 11,
"from": "2022-08-01",
"to": "2022-08-05",
"description": "test 1"
},
{
"id": 2,
"hospital_name": "hospital 12",
"hospital_id": 12,
"from": "2022-08-06",
"to": "2022-08-10",
"description": "test 2"
}
]
}
So I expect the results like that
I try to type my code like this :
data.flatMap((period) =>
period.files.map((file) => ({
id: period.id,
hospital_name: file.hospital_name,
hospital_id: file.hospital_id,
from: period.from,
to: period.to,
description: period.description,
}))
)
But the problem is my code show duplicate id
How can I solve my problem?
Note :
Every period only has one hospital id
You don't need flatMap, just run map on periods and for each period, pick the first file to extract hospital_id and hospital_name like this:
data.map(period => {
const file = period.files[0];
return {
id: period.id,
hospital_name: file.hospital_name,
hospital_id: file.hospital_id,
from: period.from,
to: period.to,
description: period.description,
}
});
You can filter the last result like:
const j = {
"data": [{
"id": 1,
"from": "2022-08-01",
"to": "2022-08-05",
"description": "test 1",
"files": [{
"id": 1,
"hospital_name": "hospital 11",
"hospital_id": 11,
"period_id": 1
},
{
"id": 2,
"hospital_name": "hospital 11",
"hospital_id": 11,
"period_id": 1
}
]
},
{
"id": 2,
"from": "2022-08-06",
"to": "2022-08-10",
"description": "test 2",
"files": [{
"id": 3,
"hospital_name": "hospital 12",
"hospital_id": 12,
"period_id": 2
},
{
"id": 4,
"hospital_name": "hospital 12",
"hospital_id": 12,
"period_id": 2
}
]
}
]
}
console.log(j.data.flatMap((period) =>
period.files.map((file) => ({
id: period.id,
hospital_name: file.hospital_name,
hospital_id: file.hospital_id,
from: period.from,
to: period.to,
description: period.description,
}))
).filter((value, index, self) =>
index === self.findIndex((t) => (
t.id === value.id
))))
Reference:
Array.prototype.filter()
Since the objects in the files array are identical (other than the id) you can destructure the properties from the data array, and (within that) the first object of each files array, and return a new object.
const data={data:[{id:1,from:"2022-08-01",to:"2022-08-05",description:"test 1",files:[{id:1,hospital_name:"hospital 11",hospital_id:11,period_id:1},{id:2,hospital_name:"hospital 11",hospital_id:11,period_id:1}]},{id:2,from:"2022-08-06",to:"2022-08-10",description:"test 2",files:[{id:3,hospital_name:"hospital 12",hospital_id:12,period_id:2},{id:4,hospital_name:"hospital 12",hospital_id:12,period_id:2}]}]};
const out = data.data.map(obj => {
const {
from,
to,
files: [{ period_id, id, ...rest }],
description
} = obj;
return { id: period_id, from, to, description, ...rest }
});
console.log(out);
Additional information
Destructuring assignment
Rest parameters
Spread syntax
I have a array of objects, and by using the foreach or map I want to create new array from its keys:
[{
"name": "Dentist Specialist",
"category": "Roles",
"path": "cde"
},
{
"name": "Root Canal Therapy",
"category": "Procedures",
"path": "abc"
},
{
"name": "Live Course",
"category": "Course Type",
"path": "mfg"
}]
From the above array I need a new ARRAY which will look like this:
[{
"Roles": "Dentist Specialist"
},
{
"Procedures": "Root Canal Therapy"
},
{
"Course Type": "Live Course"
}]
Just replace the 2nd key with the first key and remove the rest.
You can use map here to achieve the desired result.
arr.map(({ category, name }) => ({ [category]: name }));
or
arr.map((o) => ({ [o.category]: o.name }));
const arr = [
{
name: "Dentist Specialist",
category: "Roles",
path: "cde",
},
{
name: "Root Canal Therapy",
category: "Procedures",
path: "abc",
},
{
name: "Live Course",
category: "Course Type",
path: "mfg",
},
];
const result = arr.map((o) => ({ [o.category]: o.name }));
console.log(result);
I have an object
const items = {
"123": {
"key": 123,
"name": "one name",
},
"456": {
"key": 456,
"name": "two name",
},
"789": {
"key": 789,
"name": "three name",
},
};
Need to filter this from below array, with array index as object.key
const myFilter = [123,789];
Code I am trying is as below but it returning array inedx as 0,1,2... but I need the index to be object.key.
let selectedItems = myFilter.map((key) => {
return items[key];
});
Current output :
[0:{
key: 123,
name: "one name"
}, 1: {
key: 789,
name: "three name"
}]
Expected Output
[123:{
key: 123,
name: "one name"
}, 789: {
key: 789,
name: "three name"
}]
jsfiddle - https://jsfiddle.net/kb374exh/2/
Your actual output is actually correct and the only possible result from mapping the myFilter array to the matching properties from items.
const items = {
"123": {
"key": 123,
"name": "one name",
},
"456": {
"key": 456,
"name": "two name",
},
"789": {
"key": 789,
"name": "three name",
},
};
const myFilter = [123, 789];
const selectedItems = myFilter.map((key) => items[key]);
console.log(selectedItems);
The logged output you see is including the array index. You likely are seeing the index included when logging in the browser.
If you want an array of objects where the original key is the new index then the best you can likely do is an array of length <highest key> and a bunch of "holes" that are simply undefined.
const items = {
"123": {
"key": 123,
"name": "one name",
},
"456": {
"key": 456,
"name": "two name",
},
"789": {
"key": 789,
"name": "three name",
},
};
const myFilter = [123, 789];
const selectedItems = Object.entries(items).reduce((selectedItems, [key, value]) => {
if (myFilter.includes(value.key)) selectedItems[key] = value;
return selectedItems;
}, []);
console.log(selectedItems);
If you are ok with the result being an object then you can have more succinct output, you'll basically end up with back with an object with key-value pairs filtered out.
const items = {
"123": {
"key": 123,
"name": "one name",
},
"456": {
"key": 456,
"name": "two name",
},
"789": {
"key": 789,
"name": "three name",
},
};
const myFilter = [123, 789];
const selectedItems = Object.fromEntries(Object.entries(items).filter(([, value]) => myFilter.includes(value.key)));
console.log(selectedItems);
With the below JSON content that is actually coming from an API but I'm using a json file for testing. I would like to combine the primary key and flatten the ItemList.
[{
"PrimaryKey": "123",
"ItemList": [
{
"SecondaryKey": "ABC",
"Name": "Item1",
"Description": "Sample item"
},
{
"SecondaryKey": "DEF",
"Name": "Item2",
"Description": "Another sample item"
}
],
"IgnoreThis": [
{
"SomeData": "Some Data"
}
]
}]
The output I would like is:
[{
"PrimaryKey": 123,
"SecondaryKey": "ABC",
"Name": "Item1",
"Description": "Sample Item"
},
{
"PrimaryKey": 123,
"SecondaryKey": "DEF",
"Name": "Item2",
"Description": "Another sample item"
}]
I've got the Item list being flattened by:
let items = [];
items.push(JSON.parse(fs.readFileSync('./items.json')));
let result = items.reduce((r, obj) => r.concat(obj.ItemList), []);
I've tried to use items.map to get the desired output nothing has worked, I don't think I understand how to chain .map and .reduce effectively as I get undefined as the result.
Any ideas how I can achieve this output?
You can do this by running map twice: get the PrimaryKey from the first map, then add it to all the objects inside the second map, then you flatten the array you got from the previous stage.
const data = [
{
PrimaryKey: "123",
ItemList: [
{
SecondaryKey: "ABC",
Name: "Item1",
Description: "Sample item",
},
{
SecondaryKey: "DEF",
Name: "Item2",
Description: "Another sample item",
},
],
IgnoreThis: [
{
SomeData: "Some Data",
},
],
},
{
PrimaryKey: "456",
ItemList: [
{
SecondaryKey: "ABC",
Name: "Item1",
Description: "Sample item",
},
{
SecondaryKey: "DEF",
Name: "Item2",
Description: "Another sample item",
},
],
IgnoreThis: [
{
SomeData: "Some Data",
},
],
},
];
const result = data.map(({ PrimaryKey, ItemList }) => ItemList.map(item => ({
PrimaryKey,
...item,
}))).flat();
console.log(result);
I am reading a simple data set from a data.txt file. I would like to take this data and transform it into a specific object as per my example below. I have managed to get it into a somewhat usable JSON object but this is not ideal. I have included an example of the desired object.
Here is my app.js file:
let output = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
customers.push({
name: line[0],
product: [{
item: line[1],
serial: line[2],
year: line[3]
}]
})
return customers
}, [])
console.log(JSON.stringify(output, null, 2))
This currently the above NodeJs code returns the following array object:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
}
]
},
{
"name": "John",
"product": [
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
What I am trying to do is get the below object returned - ideally still following the same functional approach:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
},
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
},
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
},
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
},
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
Here is my mock data set that lives in data.txt
Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011
Instead of an array you can use Map in reduce as accumulator, use name as key in Map and club value of all keys, finally just get the values Map to get desired output
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`
const final = data.split('\n')
.map(v => v.split(';'))
.reduce((op, [name, item, serial, year]) => {
let obj = { item, serial, year }
if (op.has(name)) {
op.get(name).products.push(obj)
} else{
op.set(name,{name, products:[obj]})
}
return op
}, new Map())
console.log([...final.values()])
Here is a "functional version" that utilizes a Map to find duplicates in O(1):
(map => (
fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.forEach(([name, item, serial, year]) =>
map.has(name)
? map.get(name).product.push({ item, serial, year })
: map.set(name, { name, product: [{ item, serial, year }] })
),
[...map.values()]
)(new Map)
But seriously, whats so bad about imperative style?:
const customers = new Map;
const entries = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n');
for(const entry of entries) {
const [name, item, serial, year] = entry.split(";");
const product = { item, serial, year };
if(customers.has(name)) {
customers.get(name).product.push(product);
} else customers.set(name, { name, product: [product] });
}
const result = [...customers.values()];
You can modify the .reduce function to only add a new item to the array if there isn't one with that name. If there is, just add the product to that item's product array.
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`;
const result = data.trim()
.split('\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
const product = {
item: line[1],
serial: line[2],
year: line[3]
};
const customer = customers.find(({
name
}) => name === line[0]);
if (customer) {
customer.product.push(product);
} else {
customers.push({
name: line[0],
product: [product]
});
}
return customers
}, []);
console.log(result);