Related
I have the following array of objects:
[
{
"id": 1,
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"id": 1,
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
{
"id": 2,
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
]
I need to restructure it, so it combines the objects by ID, and creates a new nested array of objects:
[
{
"id": 1,
"prices": [
{
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
]
}
{
"id": 2,
"prices": [
{
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
]
}
]
Is there a simple way to do this? I'm getting lost in split, forEach and maps. Thanks.
One way is to use a Map to collect the prices per id. First associate an empty prices list for each id, then iterate the data to populate those arrays, and finally extract the Map values to get the result:
const data = [{"id": 1,"price": 22,"from": "00:00:00","to": "02:00:00"},{"id": 1,"price": 23,"from": "02:00:00","to": "04:00:00"},{"id": 2,"price": 10,"from": "04:00:00","to": "1.00:00:00"}];
const map = new Map(data.map(({id}) => [id, { id, prices: [] }]));
for (const {id, ...rest} of data) map.get(id).prices.push(rest);
const result = [...map.values()];
console.log(result);
Grouping by hash can save you from calling .find() or .findIndex()
const data=[{id:1,price:22,from:"00:00:00",to:"02:00:00"},{id:1,price:23,from:"02:00:00",to:"04:00:00"},{id:2,price:10,from:"04:00:00",to:"1.00:00:00"}];
const result = Object.values(data.reduce((acc, { id, ...rest }) => {
acc[id] ??= { id, prices: [] };
acc[id].prices.push(rest);
return acc;
}, {}));
console.log(result);
.as-console-wrapper {max-height: 100% !important; top: 0}
You can use the Array.reduce method with Array.findIndex to convert your data.
const data = [{
"id": 1,
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"id": 1,
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
{
"id": 2,
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
];
const transformedData = data.reduce((acc, item) => {
const priceData = {
price: item.price,
to: item.to,
from: item.from,
};
const index = acc.findIndex(({
id
}) => id === item.id);
if (index === -1) {
return [
...acc,
{
id: item.id,
prices: [
priceData
]
},
];
} else {
acc[index].prices.push(priceData);
return acc;
}
}, []);
console.log(transformedData);
const items = [
{
"id": 1,
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"id": 1,
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
{
"id": 2,
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
]
const result = items
.map(i => i.id)
.filter((item, pos, self) => self.indexOf(item) == pos)
.map( i => ({
id : i,
prices : items
.filter(item => item.id === i)
.map(({ price, from, to}) => ({price, from , to}) )
}) )
console.log(result)
Yes, there is an easy way using reduce().
const input = [
{
id: 1,
price: 22,
from: "00:00:00",
to: "02:00:00",
},
{
id: 1,
price: 23,
from: "02:00:00",
to: "04:00:00",
},
{
id: 2,
price: 10,
from: "04:00:00",
to: "1.00:00:00",
},
];
const output = input.reduce((nested, cur) => {
const objWithoutId = (({id, ...o}) => o)(cur);
if (!nested[cur.id]) {
nested[cur.id] = {
id: cur.id,
prices: [objWithoutId]
};
}
else nested[cur.id].prices.push(objWithoutId);
return nested;
}, {});
console.log(Object.values(output));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Explanation
We loop over the input using a JavaScript object. For every object we check it's ID. When we don't have that ID stored in our object already we create a new object containing the id and a prices array as well as the current value (without the id property). If we have encountered the same id already we already just need to push the current value (without the id property) to the already existing array.
Since we only have one loop and the lookups take O(1) time this algorithm takes O(n) to give a valid result.
Using this one-liner
const objWithoutId = (({id, ...o}) => o)(cur);
we create a new object which contains all properties except id.
Lat but not least we just need to get the values of the created JavaScript object using Object.values(). Instead of a JavaScript object you could also use a Map to perform the equivalent algorithm with the same runtime properties.
You can use the Object.entries, Array#reduce and Array#map methods as follows:
const input = [ { "id": 1, "price": 22, "from": "00:00:00", "to": "02:00:00" }, { "id": 1, "price": 23, "from": "02:00:00", "to": "04:00:00" }, { "id": 2, "price": 10, "from": "04:00:00", "to": "1.00:00:00" } ],
output = Object.entries(input.reduce(
(acc, {id,...rest}) =>
({...acc, [id]: [...(acc[id] || []), rest]}), {}
))
.map(([id, prices]) => ({id,prices}));
console.log( output );
I have an express server which I have GET and POST, and as original state, I have the following:
let orders = [
{
sum: 0,
purchases: [
{
id: 1,
contractId: 55,
value: 100,
},
{
id: 2,
contractId: 55,
value: -100,
}
]
}
]
// this function is running on GET request
export const getOrders = (req, res) => {
reply.status(200).send(orders)
}
export const addOrder = (req, res) => {
const newOrder = req.body
orders.map((order) => {
const correspondingorder = order.purchases.find(
(purshase) => purshase.contractId === newOrder.contractId
)
if (correspondingorder) {
order.purchases.push(newOrder)
order.sum += newOrder.value
} else {
const newValues = { sum: newOrder.value, purchases: Array(newOrder) }
orders.push(newValues)
}
}
}
My intention here is to search in the list of orders if the new added order ID is exist, if so, then add it to the list of corresponding purchases, otherwise, create a new object containing a sum and the new order, but whenever I try to add a new order with the same id then it add it to the found contractID PLUS creating a new object containing a sum and new order.
here is an example of what I get after my first POST and then GET:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
}
]
then my second attempts of adding a different order with POST:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
},
{
"sum": 100,
"purchases": [
{
"id": 3,
"contractId": 44,
"value": 100
}
]
}
]
then another post and got this results:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
},
{
"sum": 200,
"purchases": [
{
"id": 3,
"contractId": 44,
"value": 100
},
{
"id": 4,
"contractId": 44,
"value": 100
}
]
},
{
"sum": 100,
"purchases": [
{
"id": 4,
"contractId": 44,
"value": 100
}
]
}
]
any idea why this weird behavior is happening?
This is because orders.map returns a new object and doesn't mutate the original, you can override the original with:
orders = orders.map((order) => {
const correspondingorder = order.purchases.find(
(purshase) => purshase.contractId === newOrder.contractId
)
if (correspondingorder) {
order.purchases.push(newOrder)
order.sum += newOrder.value
} else {
const newValues = { sum: newOrder.value, purchases: Array(newOrder) }
orders.push(newValues)
}
}
}
But honestly, I don't recommend mutating Objects in this context, because more than 1 request can be reading/writing that variable.
If you really need to use this approach, use Array.forEach and reference the original object instead of map (that returns a new array and doesn't mutate the original one)
{
"took": 72,
"hits": {
"total": {
"value": 10000
}
},
"aggregations": {
"2": {
"buckets": [{
"key": "Perf",
"doc_count": 159874
}]
}
}
}
Could someone guide me to take the value of buckets
The built-in JSON should do the heavy lifting for you:
const str = '{ "took": 72, "hits": { "total": { "value": 10000 } }, "aggregations": { "2": { "buckets": [{ "key": "Perf", "doc_count": 159874 }] } } }';
const obj = JSON.parse(str);
the_arry = obj['aggregations']['2']['buckets'];
This should work:
var myrs = { "took": 72, "hits": { "total": { "value": 10000 } }, "aggregations": { "2": { "buckets": [{ "key": "Perf", "doc_count": 159874 }] } } };
for(var i in myrs["aggregations"]) {console.log(myrs["aggregations"][i]['buckets']);}
You can start by parsing the JSON string with var obj = JSON.parse(). It gives you an object representation of the string to work on. Log the object to the console to easily discover the structure console.log(obj); or use an online JSON viewer to do that.
Assuming the structure is fixed, the buckets array can be accessed by var buckets = obj.aggregations["2"].buckets. Notice the access of the property 2.
I have a question about sorting a dictionary object is JS es6. I am trying to filter the array but still keep the structure of an array in each month's object. Here is a mock of the data:
"soldListings": {
"Jan - 2020": [
{
"id": 159,
"user_id": 1,
"type_id": 1,
},
{
"id": 173,
"user_id": 1,
"type_id": 1,
},
{
"id": 563,
"user_id": 1,
"type_id": 2,
}
],
"Dec - 2019": [
{
"id": 183,
"user_id": 1,
"type_id": 1,
}
],
"Oct - 2019": [
{
"id": 176,
"user_id": 1,
"type_id": 1,
}
]
}
If it were a flat array of objects i would do something like:
typeFilter = data.filter((listing) => {
if(listing.type_id){
return listing.type_id == this.state.soldListTypeFilter ;
}
});
UPDATE
I need the output to be in the same format as the input. For example if i were to filter the object by type_id = 2 it would return this:
"soldListings": {
"Jan - 2020": [
{
"id": 563,
"user_id": 1,
"type_id": 2,
}
],
"Dec - 2019": [
],
"Oct - 2019": [
]
}
Use keySort function for this problem, for un-integer keys
Read https://stackoverflow.com/a/23202095/7146552
keySort( object, sortfn? )
function keySort(obj, sort) {
var keys = Object.keys(obj);
keys = keys.sort(sort);
var sortedObject = {};
for (var i = 0; i < keys.length; i++) {
sortedObject[keys[i]] = obj[keys[i]]
}
return sortedObject;
}
// Using
var obj = {
"z:": "Zvalue",
"a": "AValue"
};
console.log(obj);
obj = keySort(obj);
// or
obj = keySort(obj, (a, b) => {
return a > b ? 1 : -1
});
console.log(obj)
On your Question Test
function keySort(obj, sort) {
var keys = Object.keys(obj);
keys = keys.sort(sort);
var sortedObject = {};
for (var i = 0; i < keys.length; i++) {
sortedObject[keys[i]] = obj[keys[i]]
}
return sortedObject;
}
data = {
"Jan - 2020": [{
"id": 159,
"user_id": 1,
"type_id": 1,
},
{
"id": 173,
"user_id": 1,
"type_id": 1,
},
{
"id": 563,
"user_id": 1,
"type_id": 2,
}
],
"Dec - 2019": [{
"id": 183,
"user_id": 1,
"type_id": 1,
}],
"Oct - 2019": [{
"id": 176,
"user_id": 1,
"type_id": 1,
}]
}
data = keySort(data,function(a,b){
adate = new Date(a);
bdate = new Date(b);
return adate>bdate ? 1 : -1;
})
console.log(data);
How can I groupby data with count using lodash javascript
"data": [
{
"id": 27,
"getOrderDetail": [
{
"id": 49,
"order_id": 27,
"product_id": 1,
"product_detail":[...some data...]
},
{
"id": 51,
"order_id": 27,
"product_id": 2,
"product_detail":[...some data...]
}
{
"id": 52,
"order_id": 27,
"product_id": 1,
"product_detail":[...some data...]
}
],
"getOrderStatus": []
},
]
I want to group by product_id in getOrderDetail and count it into qty for example
"data": [
{
"id": 27,
"getOrderDetail": [
{
"id": 49,
"qty": 2,
"order_id": 27,
"product_id": 1,
"product_detail":[...some data...]
},
{
"id": 51,
"order_id": 27,
"qty": 1,
"product_id": 2,
"product_detail":[...some data...]
}
],
"getOrderStatus": []
},
]
I want to do something like this
_.countBy(data, 'getOrderDetail.product_id'); and put data count into qty field
Here is what I try
let result = _.map(totalData, function(totalData, key) {
let mapData = _.groupBy(totalData.getOrderDetail, function({ product_id }) {
return product_id;
});
});
I console.log (mapData) output look like this
{
'1': [
{
id: 49,
product_id: 1,
}
],
'2': [
{
id: 51,
product_id: 2,
}
]
}
still find looking into how can I can conunt qty
You can use _.groupBy() and then map the results, and get the qty by applying _.size() to the group, and get getOrderDetail by merging the group members, concating the arrays, and spreading back to the object:
const data = [{"id":27,"getOrderDetail":[{"id":49,"order_id":27,"product_id":1,"product_detail":[]},{"id":51,"order_id":27,"product_id":2,"product_detail":[]},{"id":52,"order_id":27,"product_id":1,"product_detail":[]}],"getOrderStatus":[]}];
const result = data.map(o => ({
...o,
getOrderDetail: _.map(
_.groupBy(o.getOrderDetail, 'product_id'),
group => ({
qty: _.size(groups),
..._.mergeWith({}, ...groups, (ov, sv) =>
_.isArray(ov) ? ov.concat(sv) : sv
)
})
)
}));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>