Rename keys in grouped array to represent the date they are grouped by - javascript

I have an array that I have grouped by 1 minute, relative to the rest of the date, except for seconds. The problem now is that the keys of each group in the array (3 groups) are just named 0, 1, 2 etc. and I want them to be named to the date they represent which they have been grouped by already.
Like so:
[
"Fri Jan 31 2020 14:58": [
{
"_id": "5e34326b1da7e21c04ec76e8",
"message": "15",
"room": "5e32c3f858f00d4ef5f9ab81",
"createdAt": 1580479083,
"user": "5e10e7a6a69a4a36e4169bdc",
"__v": 0
},
{
"_id": "5e34327e1da7e21c04ec76e9",
"message": "hello",
"room": "5e32c3f858f00d4ef5f9ab81",
"createdAt": 1580479102,
"user": "5e10e7a6a69a4a36e4169bdc",
"__v": 0
},
{
"_id": "5e34328c1da7e21c04ec76ea",
"message": "156",
"room": "5e32c3f858f00d4ef5f9ab81",
"createdAt": 1580479116,
"user": "5e10e7a6a69a4a36e4169bdc",
"__v": 0
}
]
]
See the code snippet, how can I achieve this?
const messages = [{"_id":"5e34326b1da7e21c04ec76e8","message":"15","room":"5e32c3f858f00d4ef5f9ab81","createdAt":1580479083,"user":"5e10e7a6a69a4a36e4169bdc","__v":0},{"_id":"5e34327e1da7e21c04ec76e9","message":"hello","room":"5e32c3f858f00d4ef5f9ab81","createdAt":1580479102,"user":"5e10e7a6a69a4a36e4169bdc","__v":0},{"_id":"5e34328c1da7e21c04ec76ea","message":"156","room":"5e32c3f858f00d4ef5f9ab81","createdAt":1580479116,"user":"5e10e7a6a69a4a36e4169bdc","__v":0},{"_id":"5e344bbc97cbc523d46acfad","message":"Newer","room":"5e32c3f858f00d4ef5f9ab81","createdAt":1580485564,"user":"5e10e7a6a69a4a36e4169bdc","__v":0},{"_id":"5e344e3a744b240a5cf7c9b5","message":"Newest ","room":"5e32c3f858f00d4ef5f9ab81","createdAt":1580486202,"user":"5e10e7a6a69a4a36e4169bdc","__v":0},{"_id":"5e344e3e744b240a5cf7c9b6","message":"Newest 1","room":"5e32c3f858f00d4ef5f9ab81","createdAt":1580486206,"user":"5e10e7a6a69a4a36e4169bdc","__v":0}];
const sortByDate = _.chain(messages)
.groupBy(m => {
const d = new Date(m.createdAt * 1000);
console.log(d);
return Math.floor(+(d) / (1000*60));
})
.sortBy((v, k) => { return k; })
.value();
console.log(sortByDate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js" type="text/javascript"></script>

I managed to solve it with just _.groupBy and momentjs.
const sortByMinute = _.groupBy(messages, function (date) {
return moment(date.createdAt*1000).startOf("minute").format();
});
It groups them by minute and the returned object is named accordingly!

You could achieve that as this:
messages.map((message) => {
d = new Date(message.createdAt);
d.setMinutes(0);
d.setSeconds(0);
arr.push({[d]:message});
});
Hope it helps :)

Related

convert all array object(firestore timestamp) to date

I am using firestore and react-native-gifted-chat, I am trying to get all the chat messages from firestore to the chat. However, gifted chat does not support displaying firebase timestamp. It will show invalid Date. Therefore, I m trying to convert all the date object.
async _getMessage() {
const messColRef = db.collection('Message').doc(this.state.roomName).collection('message').orderBy('createdAt', 'desc').limit(9)
const initialQuery = messColRef
const documentSnapshots = await initialQuery.get()
const documentData = documentSnapshots.docs.map(document => ({
id: document.id, ...document.data()
}));
const lastVisible = documentData[documentData.length - 1]
const finalData = _.forEach(documentData['createdAt'], (item) => {
return item.toDate()
});
console.log(documentData)
}
and it is how my data look like:
{
"_id": "f0feb0b6-c0f9-4735-a93d-4297872a4840",
"createdAt": Timestamp {
"nanoseconds": 382000000,
"seconds": 1568995812,
},
"id": "Uw6PNNsf7aqWrxcgSDSi",
"text": "Hi",
"user": {
"_id": "V8h2iSllhPXSr8sTGP0yHiaYZwx1",
"avatar": "https://firebasestorage.googleapis.com/v0/b/exit-3684f.appspot.com/o/add-
user.png ? alt = media & token=395c8beb - 47a3 - 4ae6 - a0a1 - fe901e7ad42f",
"name": "This is the username",
},
},
{
"_id": "cc298d96-f19a-4ec7-bdf7-3767d900a364",
"createdAt": Timestamp {
"nanoseconds": 373000000,
"seconds": 1568995733,
},
"id": "WzbOA52Y3qukvPUIXRLB",
"text": "hello",
"user": {
"_id": "V8h2iSllhPXSr8sTGP0yHiaYZwx1",
"avatar": "https://firebasestorage.googleapis.com/v0/b/exit-3684f.appspot.com/o/add-
user.png ? alt = media & token=395c8beb - 47a3 - 4ae6 - a0a1 - fe901e7ad42f",
"name": "This is the username",
},
},
so my goal is to convert all the createdAt to js time date
Sorry for not explore deeply, after checking #Spatz comments I figure out how to do it
documentData.forEach(a => {
var date = a.createdAt.toDate()
data.push({
_id: a._id,
createdAt: date,
id: a.id,
text: a.text,
user: a.user
})
})
Use renderTime prop of gifted chat and pass a function which converts the time and return that time in a string.

How to generate an array of unique objects from api?

I'm trying to disable booked times from calendar, depending on the date. My goal is to create an array, which holds objects with single date and array of booked times.
I have created an api, which outputs something like this:
"bookings": [
{
"_id": "5ce1b8792598adasf452",
"workType": "Nail polishing",
"client": "Mary Johnson",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "09:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "10:00"
}
]
I've tried using Sets, filters, but I just can't seem to wrap my head around how to implement it to my own code.
Snippet of my code:
bookedTimes: []
fetchBookedTimes() {
axios.get("http://localhost:8080/api/bookings").then(res => {
for (var i = 0; i < res.data.bookings.length; i++) {
this.bookedTimes.push({
date: moment(res.data.bookings[i].date).format("YYYY-MM-DD"),
times: [res.data.bookings[i].bookingTime.substring(0,2)]
});
}
});
}
I expect the output to be
bookedTimes: [
{
date: "2019-05-31",
times: ["09", "10"]
},
{
date: "2019-06-01",
times: ["10", "11"]
}
]
But the actual output is
bookedTimes: [
{
date: "2019-05-31",
times: ["09"]
},
{
date: "2019-05-31",
times: ["10"]
},
{
date: "2019-06-01",
times: ["10"]
},
{
date: "2019-06-01",
times: ["11"]
}
]
As per the code, the actual output is correct. You are looping the response and pushing the data to an array. If you want to group them by date, then you have to create an object and then convert it to the expected output.
var result = res.data.bookings.reduce(function (defaultValue, booking) {
var date = moment(booking.date).format("YYYY-MM-DD");
defaultValue[date] = defaultValue[date] || {date: date, times: []};
defaultValue[date].times.push(booking.bookingTime.substring(0,2));
return defaultValue;
}, {});
console.log(Object.values(result));
You can simply use reduce()
const arr = [
{
"_id": "5ce1b8792598adasf452",
"workType": "Nail polishing",
"client": "Mary Johnson",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "09:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-05-31T00:00:00.000Z",
"bookingTime": "10:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-06-31T00:00:00.000Z",
"bookingTime": "11:00"
},
{
"_id": "5ce1b8753hs53gasf452",
"workType": "Makeup",
"client": "Kate Bush",
"date": "2019-06-31T00:00:00.000Z",
"bookingTime": "12:00"
}
]
const res = arr.reduce((ac,{date,bookingTime}) => {
ac[date] = ac[date] || {date,bookingTime:[]}
ac[date].bookingTime.push(bookingTime.slice(0,2));
return ac;
},{})
console.log(Object.values(res))
You're pushing values directly into array but you need to group them by date so you can use an object and then push values to array in the end
Here temp is used to group values by date
We check for date it exists we push the time value to times array if not we create a new property on temp
In the end we push values to this.bookedTimes array
fetchBookedTimes() {
axios.get("http://localhost:8080/api/bookings").then(res => {
let temp = {}
for (var i = 0; i < res.data.bookings.length; i++) {
let date = moment(res.data.bookings[i].date).format("YYYY-MM-DD"),
let time = [res.data.bookings[i].bookingTime.substring(0,2)]
temp[date] = temp[date] || {date: date, times:[]}
temp[date].times.push(time)
});
}
this.bookedTimes.push(Object.values(temp))
});
}
First, check if the date of already in the array. Check if 'times' already exist in 'object.times', if not, push it to the 'object.times' array.
Please see the code below.
const date = moment(res.data.bookings[i].date).format("YYYY-MM-DD");
const times = res.data.bookings[i].bookingTime.substring(0, 2);
const arrayIndex = bookedTimes.findIndex(item => item.date === date);
//Check if date already exist in array
if (arrayIndex !== -1) {
//Check if 'times' already exist in 'object.times'
if (!bookedTimes[arrayIndex].times.includes(times)) {
//Push 'times' in 'object.times'
bookedTimes[arrayIndex].times.push(times);
}
} else {
//Push a new object into the array
bookedTimes.push({
date: date,
times: [times]
});
}

Dynamic swapping of key/values in a Javascript object

I'm about to show the data I aggregated from the database in a grouped histogram.
The data looks like this:
[
{
"_id": "Gas Separator Filter",
"sellingPrice": 100000,
"quantity": 10
},
{
"_id": "Dry Gas Cartridge",
"sellingPrice": 6005000,
"quantity": 15
}
]
But in order to show it in the chart and for them to be grouped, I need something like this. For each _id in the dataset above I should be able to see two bars in the chart.
[
{
"name": "quantity",
"Gas Separator Filter": 10,
"Dry Gas Cartridge": 15
},
{
"name": "sellingPrice",
"Gas Separator Filter": 100000,
"Dry Gas Cartridge": 6005000
}
]
It's been two hours and I'm not able to think of a good way to do this. What will you suggest?
Here is one solution using old school for loops :)
const transform = (data, nameValues, keyProp) => {
const result = [];
for (const name of nameValues) {
const output = { name };
for (const value of data) {
output[value[keyProp]] = value[name];
}
result.push(output);
}
return result;
};
const result = transform(
[
{
"_id": "Gas Separator Filter",
"sellingPrice": 100000,
"quantity": 10
},
{
"_id": "Dry Gas Cartridge",
"sellingPrice": 6005000,
"quantity": 15
}
],
["sellingPrice", "quantity"],
"_id"
);
console.log(result);
You can use array.reduce to achieve this:
const arrayToArray = (array) => {
var ret = [{
"name": "price"
}, {
"name": "quantity"
}
];
return array.reduce((obj, item, idx, original) => {
ret[0][item._id] = original[idx].sellingPrice;
ret[1][item._id] = original[idx].quantity;
return ret;
}, 0)
}
Like this you set a variable with the base object that you fullfill with couple _id:value for price and quantity.
But is not an "elegant" way to do this. Are you sure you need this objects array structure to show the chart?
I find it hard to explain my solution but here's my take on it (you can add console.logs for different variables to follow the transformation ):
extract all the keys in the object, loop through them, the name would be that key, and use a nested loop to set the other keys and values :
const data = [ { "_id": "Gas Separator Filter", "sellingPrice": 100000, "quantity": 10 }, { "_id": "Dry Gas Cartridge", "sellingPrice": 6005000, "quantity": 15 } ]
const [_id, ...keys] = [...new Set(data.map(e => Object.keys(e)).flat())]
// console.log(keys) : ["sellingPrice", "quantity"]
const result = keys.map(key => {
const values = data.map(obj => ({
[obj._id]: obj[key]
}))
return Object.assign({
name: key
}, ...values);
})
console.log(result)

Sorting array of object javascript / typescript on firestore timestamp

I have below array structure
[
{
"id": "8gFUT6neK2I91HIVkFfy",
"element": {
"id": "8gFUT6neK2I91HIVkFfy",
"archived": false,
"updatedOn": {
"seconds": 1538653447,
"nanoseconds": 836000000
}
},
"groupBy": "pr"
},
{
"id": "9jHfOD8ZIAOX4fE1KUQc",
"element": {
"id": "9jHfOD8ZIAOX4fE1KUQc",
"archiveDate": {
"seconds": 1539250407,
"nanoseconds": 62000000
},
"archived": false,
"updatedOn": {
"seconds": 1538655984,
"nanoseconds": 878000000
}
},
"groupBy": "pr"
},
{
"id": "CeNP27551idLysSJOd5H",
"element": {
"id": "CeNP27551idLysSJOd5H",
"archiveDate": {
"seconds": 1539248724,
"nanoseconds": 714000000
},
"archived": false,
"updatedOn": {
"seconds": 1538651075,
"nanoseconds": 235000000
}
},
"groupBy": "pr"
},
{
"id": "Epd2PVKyUeAmrzBT3ZHT",
"element": {
"id": "Epd2PVKyUeAmrzBT3ZHT",
"archiveDate": {
"seconds": 1539248726,
"nanoseconds": 226000000
},
"archived": false,
"updatedOn": {
"seconds": 1538740476,
"nanoseconds": 979000000
}
},
"groupBy": "pr"
}
]
and below code to sort
Sample JSfiddle
http://jsfiddle.net/68wvebpz/
let sortedData = this.arraydata.sort((a:any, b:any) => { return Number(new Date(b.element.date).getTime()) - Number(new Date(a.element.date).getTime()) })
This does not make any effect.
There are a few problems that we need to fix:
Your updatedOn object is not something that can be converted to a date. You need to do extra work.
JavaScript doesn't support nanoseconds, only milliseconds. You will therefore need to divide that number by a million.
By using getTime for the comparison, you're actually discarding the milliseconds - that function returns seconds.
To fix the first two, use this function:
function objToDate(obj) {
let result = new Date(0);
result.setSeconds(obj.seconds);
result.setMilliseconds(obj.nanoseconds/1000000);
console.log('With nano', result);
return result;
}
This creates a new date and then sets the seconds and milliseconds. This gives you dates in October 2018 when I use your test data.
Then, to compare them and fix the remaining problems, use this (much simpler) form:
let sortedData = data.sort((a:any, b:any) => {
let bd = objToDate(b.element.updatedOn);
let ad = objToDate(a.element.updatedOn);
return ad - bd
});
That should do it.
To reverse the sort order, just use the less-than operator:
return bd - ad
Turn your strings into dates, and then subtract them to get a value that is either negative, positive, or zero:
array.sort(function(a,b){
return new Date(b.date) - new Date(a.date);
});
Is it something like this:
var array = [
{id: 1, name:'name1', date: 'Mar 12 2012 10:00:00 AM'},
{id: 2, name:'name2', date: 'Mar 8 2012 08:00:00 AM'}
];
console.log(array.sort((a, b) => {
return new Date(a.date) - new Date(b.date)
}))

Javascript: group by with aggregation

I have a simple json list like the one below
{
"myList": [
{
"endOfPeriod": 1461362400000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461535200000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461967200000,
"rate": 0.03708314
},
{
"endOfPeriod": 1461708000000,
"rate": 0.03492851
},
{
"endOfPeriod": 1461794400000,
"rate": 0.03845068
},
{
"endOfPeriod": 1461621600000,
"rate": 0.03544827
}
]
}
Where endOfPeriod is a unix epoch timestamp. All the timestamps in the example belong to the same month (April 2016), but could be some other periods.
Assuming that I have already converted this json list into an array, and each unix timestamp into a DD.MM.YYYY date (I can keep them in unix timestamp too). Is there an efficient way to create a new array with the most recent rate for grouped by month/year?
I have to write code in Javascript.
For instance:
20.04.2016 / 0.33
21.04.2016 / 0.55
14.04.2016 / 0.88
02.05.2016 / 1.33
01.05.2016 / 5.44
New array must contain:
21.04.2016 / 0.55
02.05.2016 / 1.33
Thanks for your help.
If I understand correctly, you want to extract the most recent rate for each month. I would use lodash.
_.chain(arr)
.groupBy(function(item) {
var date = new Date(item.endOfPeriod);
return date.getFullYear() + '-' + date.getMonth();
})
.map(function(group) {
return _.maxBy(group, function(item) {
return item.endOfPeriod;
});
})
.value()
We start with a list of objects in the form:
{
"endOfPeriod" : 1464818400000,
"rate" : 0.05
}
The chain() function wraps the list into a lodash object.
Then, we group elements by year and month. After the groupBy(), we have the following structure (note that getMonth() is 0-based in Javascript, hence a value of 3 corresponds to April, and so on):
{
"2016-3" : [array of objects in April 2016],
"2016-4" : [array of objects in May 2016]
...
}
Then, for each group, we take the item with maximum endOfPeriod.
Finally, value() unwraps the lodash object back into a plain Javascript array.
Here is a result without using lodash. But for me it's better not to reinvent the wheel.
const myList = [
{
"endOfPeriod": 1461362400000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461535200000,
"rate": 0.03726378
},
{
"endOfPeriod": 1461967200000,
"rate": 0.03708314
},
{
"endOfPeriod": 1461708000000,
"rate": 0.03492851
},
{
"endOfPeriod": 1461794400000,
"rate": 0.03845068
},
{
"endOfPeriod": 1461621600000,
"rate": 0.03544827
}
];
const res = myList.reduce((prev, current) => {
const date = new Date(current.endOfPeriod);
const month = date.getMonth();
const year = date.getFullYear();
const key = `${year}-${month}`;
if (prev[key] && prev[key].endOfPeriod < current.endOfPeriod) {
prev[key] = current;
} else {
prev[key] = current;
}
return prev;
}, {});
const finalResult = Object.keys(res).map((key) => {
return {
key: res[key].rate
}
});
console.log(finalResult);

Categories