Parsing JSON and grouping multiple array values - javascript

I have a JSON response that looks like the following
{
data: [
{
attributes:[
{
type: 'size',
value: '10'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [
{
store_id: '1000',
stock: '10'
},
{
store_id: '2000',
stock: '3'
},
{
store_id: '3000',
stock: '5'
}
]
},
{
attributes:[
{
type: 'size',
value: '9'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [
{
store_id: '1000',
stock: '10'
},
{
store_id: '2000',
stock: '3'
},
{
store_id: '4000',
stock: '5'
}
]
},
{
attributes:[
{
type: 'size',
value: '7'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [
{
store_id: '1000',
stock: '19'
},
{
store_id: '2001',
stock: '8'
},
{
store_id: '4000',
stock: '2'
}
]
}
]
}
Using JS I'm trying to parse the values and get something that sorts each value via the store ID
e.g
using the data above this is what I would like to achieve
array['2000'] = ['10 - (3)', '9 - (3)', '7 - (8)']
2000 being the store_id
array values being size - (stock)

The simple way is to use Array#reduce to aggregate your data.
Besides, in each inventory you should integrate all items to define the value with correct structure like ${attributes[0].value} - (${stock})
const yourJson = {data:[{attributes:[{type:'size',value:'10'},{type:'colour',value:'red'}],inventory:[{store_id:'1000',stock:'10'},{store_id:'2000',stock:'3'},{store_id:'3000',stock:'5'}]},{attributes:[{type:'size',value:'9'},{type:'colour',value:'red'}],inventory:[{store_id:'1000',stock:'10'},{store_id:'2000',stock:'3'},{store_id:'4000',stock:'5'}]},{attributes:[{type:'size',value:'7'},{type:'colour',value:'red'}],inventory:[{store_id:'1000',stock:'19'},{store_id:'2001',stock:'8'},{store_id:'4000',stock:'2'}]}]};
const result = yourJson.data.reduce((acc, {attributes, inventory}) =>
{
for(const {store_id, stock} of inventory){
acc[store_id] = acc[store_id] ||[];
acc[store_id].push(`${attributes[0].value} - (${stock})`);
}
return acc;
}, {});
console.log(result);

You want to use reduce() for that to select the item on the inventory.
Here's an example:
let response = {
data: [
{
attributes:[
{
type: 'size',
value: '10'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [
{
store_id: '1000',
stock: '10'
},
{
store_id: '2000',
stock: '3'
},
{
store_id: '3000',
stock: '5'
}
]
},
{
attributes:[
{
type: 'size',
value: '9'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [
{
store_id: '1000',
stock: '10'
},
{
store_id: '2000',
stock: '3'
},
{
store_id: '4000',
stock: '5'
}
]
},
{
attributes:[
{
type: 'size',
value: '7'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [
{
store_id: '1000',
stock: '19'
},
{
store_id: '2001',
stock: '8'
},
{
store_id: '4000',
stock: '2'
}
]
}
]
}
let selected_inventory = response.data.reduce((a, b) => a = b.inventory.find(inv => inv.store_id === '2000') || a, {})
console.log(selected_inventory) // Expected Result: { "store_id": "2000", "stock": "3" }

The other answer doesn't seem to give it exactly in the format you want.
function toObj(arr) {
const obj = {};
for (const { attributes, inventory } of arr) {
// Watch out, this assumes there will always be a "size" attribute
const size = attributes.find(a => a.type === 'size').value;
for (const inv of inventory) {
// Assign array if it doesn't exist
// This will be, for ex, obj['2000']
obj[inv.store_id] = obj[inv.store_id] || [];
// Constructs and pushes the final strings
obj[inv.store_id].push(size + ' - (' + inv.stock + ')');
}
}
return obj;
}
const INPUT = {
data: [{
attributes: [{
type: 'size',
value: '10'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [{
store_id: '1000',
stock: '10'
},
{
store_id: '2000',
stock: '3'
},
{
store_id: '3000',
stock: '5'
}
]
},
{
attributes: [{
type: 'size',
value: '9'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [{
store_id: '1000',
stock: '10'
},
{
store_id: '2000',
stock: '3'
},
{
store_id: '4000',
stock: '5'
}
]
},
{
attributes: [{
type: 'size',
value: '7'
},
{
type: 'colour',
value: 'red'
}
],
inventory: [{
store_id: '1000',
stock: '19'
},
{
store_id: '2001',
stock: '8'
},
{
store_id: '4000',
stock: '2'
}
]
}
]
}
console.log(toObj(INPUT.data));

Related

How to compress duplicate elements and get their quantity values?

I need to find the elements with the same id in the array below, add their amounts and write them in a single line.
let arr = [
{ itemId: 123, name: '0', quantity: 2 },
{ itemId: 1, name: '1', quantity: 2 },
{ itemId: 13, name: '2', quantity: 2 },
{ itemId: 13, name: '3', quantity: 2 },
{ itemId: 13, name: '4', quantity: 24 },
{ itemId: 13, name: '5', quantity: 2 },
{ itemId: 1, name: '6', quantity: 4 },
{ itemId: 1, name: '7', quantity: 2 },];
I want an output like this:
[{ itemId: 123, name: '1', quantity: 2 },
{ itemId: 1, name: '2', quantity: 6 },
{ itemId: 13, name: '6', quantity: 30 }];
And my code:
const getPureList = () => {
for (let index = 0; index < arr.length; index++) {
for (let a = index + 1; a < arr.length; a++) {
if (arr[index].itemId === arr[a].itemId) {
arr[index].quantity += arr[a].quantity;
arr.splice(a, 1);
}
}
}
return arr;
};
Thanks for your help.
By keeping the name od the first object of the group, you could take an object for grouping and take the values as result.
const
array = [{ itemId: 123, name: '0', quantity: 2 }, { itemId: 1, name: '1', quantity: 2 }, { itemId: 13, name: '2', quantity: 2 }, { itemId: 13, name: '3', quantity: 2 }, { itemId: 13, name: '4', quantity: 24 }, { itemId: 13, name: '5', quantity: 2 }, { itemId: 1, name: '6', quantity: 4 }, { itemId: 1, name: '7', quantity: 2 }],
result = Object.values(array.reduce((r, o) => {
r[o.itemId] ??= { ...o, quantity: 0 };
r[o.itemId].quantity += o.quantity;
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to replace the object with the new object using javascript or lodash?

i have the datastructure like below,
const data = {
getSomething: {
id: '1',
items: [
{
id: '1',
orders: [
{
id: '1',
name: 'one1',
}
],
subItems: [
{ id: '1', name: 'subitem1' },
{ id: '2', name: 'subitem2' },
],
},
{
id: '2',
orders: [
{
id: '2',
name: 'two1',
}
],
subItems: [
{ id: '2', name: 'subitem1' },
{ id: '3', name: 'subitem2' },
],
}
],
}
}
now i have another data like below,
const item1 = {
id: '2',
orders: [
{
id: '3',
name: 'one1',
}
],
}
i have to replace the item with id 1 in data with the item1 above. how can i do it using lodash. or any other way that i can do it easily.
could someone help me with this. thanks.
const data = {
getSomething: {
id: '1',
items: [{
id: '1',
orders: [{
id: '1',
name: 'one1',
}],
subItems: [{
id: '1',
name: 'subitem1'
},
{
id: '2',
name: 'subitem2'
},
],
},
{
id: '2',
orders: [{
id: '2',
name: 'two1',
}],
subItems: [{
id: '2',
name: 'subitem1'
},
{
id: '3',
name: 'subitem2'
},
],
}
],
}
}
const item1 = {
id: '2',
orders: [{
id: '3',
name: 'one1',
}],
}
Object.assign(data.getSomething.items.find(item => item.id === item1.id),item1);
console.log(data);
Are you looking something like this ?
const data = {
getSomething: {
id: '1',
items: [
{
id: '1',
orders: [
{
id: '1',
name: 'one1',
}
],
subItems: [
{ id: '1', name: 'subitem1' },
{ id: '2', name: 'subitem2' },
],
},
{
id: '2',
orders: [
{
id: '2',
name: 'two1',
}
],
subItems: [
{ id: '2', name: 'subitem1' },
{ id: '3', name: 'subitem2' },
],
}
],
}
}
const item1 = {
id: '2',
orders: [
{
id: '3',
name: 'one1.......',
}
],
subItems: [
{ id: '2', name: 'subitem1....' },
{ id: '3', name: 'subitem2....' },
],
}
let result = data.getSomething.items.map(item=> item.id===item1.id ? ({...item1}): item);
console.log('-----Original----', data.getSomething.items);
console.log('-----Updated-----', result);
This will overwrite item with id 1 in data with the item1:
const data = {
getSomething: {
id: '1',
items: [
{
id: '1',
orders: [
{
id: '1',
name: 'one1',
}
],
subItems: [
{ id: '1', name: 'subitem1' },
{ id: '2', name: 'subitem2' },
],
},
{
id: '2',
orders: [
{
id: '2',
name: 'two1',
}
],
subItems: [
{ id: '2', name: 'subitem1' },
{ id: '3', name: 'subitem2' },
],
}
],
}
}
const item1 = {
id: '2',
orders: [
{
id: '3',
name: 'one1',
}
],
}
const oldItem = data.getSomething.items.find(item => item.id == 1);
Object.assign(oldItem, item1);
console.log(data);

How to show specific JSON data using filter or other JS method (by attribute)

Here is my JSON from an API request:
[ { name: 'PM1', value: 21.51, key: 'PM1' },
{ name: 'PM25', value: 35.08, key: 'PM25' },
{ name: 'PM10', value: 54.85, key: 'PM10' },
{ name: 'PRESSURE', value: 1021.45, key: 'PRESSURE' },
{ name: 'HUMIDITY', value: 97, key: 'HUMIDITY' },
{ name: 'TEMPERATURE', value: 10.4, key: 'TEMPERATURE' } ]
I want to remove the last 3 objects (TEMPERATURE, PRESSURE and HUMIDITY), so it would look like this:
[ { name: 'PM1', value: 21.51, key: 'PM1' },
{ name: 'PM25', value: 35.08, key: 'PM25' },
{ name: 'PM10', value: 54.85, key: 'PM10' } ]
The question is - what should I do? Using slice() is not a good option since sometimes objects might not be the same, for example, there might be no TEMPERATURE or PRESSURE. I hope I made myself clear. In case you asked, this data is going to be displayed to the user in a CLI app ;)
You can use filter and check the index. The snippet below will remove the last three items, as I believe this is what you want.
const data = [
{ name: 'PM1', value: 21.51, key: 'PM1' },
{ name: 'PM25', value: 35.08, key: 'PM25' },
{ name: 'PM10', value: 54.85, key: 'PM10' },
{ name: 'PRESSURE', value: 1021.45, key: 'PRESSURE' },
{ name: 'HUMIDITY', value: 97, key: 'HUMIDITY' },
{ name: 'TEMPERATURE', value: 10.4, key: 'TEMPERATURE' }
]
const newData = data.filter((item, index) => {
if(index < data.length - 3) {
return item;
}
})
console.log(newData);
If you want to always keep PM1, PM25 and PM10 use the following:
const data = [
{ name: 'PM1', value: 21.51, key: 'PM1' },
{ name: 'PM25', value: 35.08, key: 'PM25' },
{ name: 'PM10', value: 54.85, key: 'PM10' },
{ name: 'PRESSURE', value: 1021.45, key: 'PRESSURE' },
{ name: 'HUMIDITY', value: 97, key: 'HUMIDITY' },
{ name: 'TEMPERATURE', value: 10.4, key: 'TEMPERATURE' }
]
newData = data.filter(item => (
item.name == 'PM1' || item.name =='PM25' || item.name == 'PM10'
));
console.log(newData);
You can use filter to exclude items whose names are not in ['TEMPERATURE', 'HUMIDITY', 'PRESSURE']:
var data = [{ name: 'PM1', value: 21.51, key: 'PM1' },
{ name: 'PM25', value: 35.08, key: 'PM25' },
{ name: 'PM10', value: 54.85, key: 'PM10' },
{ name: 'PRESSURE', value: 1021.45, key: 'PRESSURE' },
{ name: 'HUMIDITY', value: 97, key: 'HUMIDITY' },
{ name: 'TEMPERATURE', value: 10.4, key: 'TEMPERATURE' }];
console.log(data.filter(d => !['TEMPERATURE', 'HUMIDITY', 'PRESSURE'].includes(d.name)));

Filter array of objects with another array of object

I want to Filter an array of objects with another array of object.The logic will be used in product search by category and color etc. This is my main Array :
products: [{
id: 1,
name: 'Product 1',
category: 'Home',
skill: 'Easy',
color: 'blue',
price: 100.00
}, {
id: 2,
name: 'Product 2',
category: 'Home',
skill: 'Intermediate',
color: 'red',
price: 120.00
}, {
id: 3,
name: 'Product 3',
category: 'Office',
skill: 'Intermediate',
color: 'green',
price: 190.00
}, {
id: 4,
name: 'Product 4',
category: 'Office',
skill: 'Advanced',
color: 'blue',
price: 260.00
}, {
id: 5,
name: 'Product 5',
category: 'Warehouse',
skill: 'Advanced',
color: 'white',
price: 321.00
}, {
id: 6,
name: 'Product 6',
category: 'Farm',
skill: 'Intermediate',
color: 'red',
price: 120.00
}, {
id: 7,
name: 'Product 7',
category: 'Space',
skill: 'Advanced',
color: 'green',
price: 150.00
}, {
id: 8,
name: 'Product 8',
category: 'Bathroom',
skill: 'Easy',
color: 'black',
price: 9.00
}]
The filter I am creating on the fly like this array.
The expected result is to filter product data by multiple selected categories and colors.
I have tried the following code :
var filtered = [];
for(var arr in self.products){
for(var filter in self.selectedFilters){
if(self.products[arr].category == self.selectedFilters[filter].category && self.products[arr].color == self.selectedFilters[filter].color){
filtered.push(self.products[arr]);
}
}
}
console.log(filtered);
myArray = [
{
userid: "100",
projectid: "10",
rowid: "0"
},
{
userid: "101",
projectid: "11",
rowid: "1"
},
{
userid: "102",
projectid: "11",
rowid: "2"
},
{
userid: "102",
projectid: "13",
rowid: "3"
},
{
userid: "101",
projectid: "10",
rowid: "4"
}
];
myFilter = [
{
userid: [
{
0: "101"
},
{
1: "102"
}
],
projectid: [
{
0: "11"
}
]
}
];
const filterFn = (array, filter) => {
let result = [];
filter.forEach(element => {
let keys = Object.keys(element);
keys.forEach(key => {
let values = Object.values(element[key]);
values = values.map(x => Object.values(x)[0]);
let ans = array.filter(e => {
if (values.includes(e[key])) return e;
});
result = result.concat(ans);
});
});
return result;
};
console.log(filterFn(myArray, myFilter));
var filtered = [];
for(var arr in myArray){
for(var filter in myFilter){
if(myArray[arr].userid == myFilter[filter].userid && myArray[arr].projectid == myFilter[filter].projectid){
filtered.push(myArray[arr].userid);
}
}
}
console.log(filtered);

How can I achieve this with Lodash?

I would like to group all messages between 2 people in a group (chat). Doesn`t matter if I am the author or receiver.
Let's say this example code.
const messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
]
Imagine, I am user ID = 1, so I would like to get this:
const chats = [
{
chatName: 'Name of user ID 2', messages: [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
]
},
{
chatName: 'Name of user ID 3', messages: [
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
]
}
];
How can I achieve this with Lodash?
Not sure about lodash, but you can use plain js - reduce and map to get that structure
const messages = [{
id: '100',
text: 'aaa',
author: {
id: '1'
},
receiver: {
id: '2'
}
},
{
id: '101',
text: 'bbb',
author: {
id: '2'
},
receiver: {
id: '1'
}
},
{
id: '102',
text: 'ccc',
author: {
id: '3'
},
receiver: {
id: '1'
}
},
];
function groupByPair(arr) {
return [
...arr.reduce((a, b) => {
let {
author,
receiver
} = b;
let s = [author.id, receiver.id].sort().join('-');
a.set(s, a.has(s) ? a.get(s).concat(b) : [b]);
return a;
}, new Map)
].map(e => ({
chatName: 'Name of user ID ' + e[0].substring(e[0].indexOf('-') + 1),
messages: e[1]
}));
}
console.log(groupByPair(messages));
Using either Lodash or Underscore.js:
var grouped = _.groupBy(messages, m => _.sortBy([m.author.id, m.receiver.id]));
var formatted = _.map(grouped, (v, name) => ({ chatname: name, messages: v }));
You could combine those into a single line, but that seems overly dense to my eyes.
I took the liberty of defining a more complex test dataset, to make sure the edge cases were better covered:
var messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
{ id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } },
{ id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } },
{ id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }
]
With this data, the code above yields a formatted of:
[
{ chatname: '1,2',
messages: [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } }
]
},
{ chatname: '1,3', messages: [
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
{ id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }
]
},
{ chatname: '3,4', messages: [
{ id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } }
]
}
]
The major difference with your desired output relates to the chatname values. I did not see how you were naming those, so I stuck with Lodash/Underscore's native groupby keys.
You can do this with _.groupby. I filter the array first so that you're only left with messages that involve user 1.
const messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
];
const filtered = messages.filter((msg) => {
return msg.author.id === '1' || msg.receiver.id === '1'
});
const groups = _.groupBy(filtered, (msg) => {
return msg.author.id === '1' ? msg.receiver.id : msg.author.id
});
console.log(groups);
<script src="https://unpkg.com/lodash#4.17.4"></script>

Categories

Resources