Sorting array by time and date using date-fns - reactjs

I have an array with blog posts that I wanted sorted by newest entry. I'm able to map through the array just fine but I want the newest entry located at the very top of the page and right now it's going to the bottom. If I sort the array by time/date I know it will work but having issues getting it to sort.
const BlogTopic = [
{
title: "First Post",
message: "test",
author: "Dagger",
date: format(new Date(), "2/13 2:09a"),
},
{
title: "Second Post",
message: "test",
author: "Dagger",
date: format(new Date(), "2/13 3:48a"),
},
];
I'm also using a form to add new entries and it's saving all the above information and adding a new object at the end of the array. When it comes to adding a date I'm using this format.
date: format(new Date(), "M/dd h:mma"),
And this is my code for sorting the array.
const [topic, setTopic] = useState(BlogTopic);
{topic
.sort((a, b) => new Date(b.date) - new Date(a.date))
.map(({ title, author, date }, index) => (
<tr>
<td className="blog__topic">
{title}
</td>
<td>{author}</td>
<td>{date}</td>
</tr>
))}
UPDATE
Here is my full state. Any ideas for how I can change the 2/17 3:48a below so it automatically takes the current date and time?
const [title, setTitle] = useState();
const addTopic = (e) => {
e.preventDefault();
setTopic([
...topic,
{
title: title,
message,
author: "Dagger",
count: 1,
date: parse("2/17 3:48a", "M/dd h:mma", new Date()),
},
]);
setTitle("");
};

Ok, so, there are a few issues with your code. I'll try to fix them by reducing your code to the simplest form possible and work our way up to what you expect.
Let's start the simplification by taking a look at the dates in the array's objects. For the first object, you have format(new Date(), "2/13 2:09a"). Given that you stated that the format is M/dd h:mma, I can easily convert this date into an ISO one: 2023/02/13 02:09:00. The benefit of doing this is that this can be feed to new Date() very easily. If we apply those operations on both objects, we have the resulting array:
const BlogTopic = [
{
title: "First Post",
message: "test",
author: "Dagger",
date: new Date("2023/02/13 02:09:00"),
},
{
title: "Second Post",
message: "test",
author: "Dagger",
date: new Date("2023/02/13 03:48:00"),
},
];
Ok, so far so good. Now, let's move to the next bit: sorting. Since the dates are now as a Date object, sorting is trivial. In fact you already provided the code for sorting, you just needed to reverse the operands:
BlogTopic.sort((a, b) => b.date - a.date)
Please, note the following:
I kept the parameters order as you had them a, b
I reversed the substraction b - a instead of a - b
Since the date parameter is already a Date object, we don't need to wrap it again
Great! Now we have an array properly sorted. The next step is about displaying this. As you saw, if you try {new Date()}, React will complaint because you are trying to display an object. What we need to do, therefore, is to turn this object into some string representation before giving it to React. For now, we will keep it simple and use the toUTCString() method (this is just for the sole purpose of simplifying your code, keep reading for your expected solution). So, now, we can do the following (again, keep in mind I'm simplifying your code for the sake of explaining all this, I know there are other parameters like title and author);
BlogTopic.map(({ date }) => (
<tr><td>{date.toUTCString()}</td></tr>
)}
Very well! So far we have managed to have an array with dates, sort it and display it so, the final piece to the puzzle is to use the format you need. As you pointed out, we will use date-fns to assist us with this. Among many other methods, this library has the following 2 that we will be using:
format: Which takes a Date object and a pattern string and outputs an string with the date in the given format
parse: Which takes a string with the date, a pattern declaring which format your date currently is and a Date object to provide defaults
The good thing about those functions is that they use the same format for the pattern string... that's handy!
Let's focus on the data input, this is your array. What you want here is to turn a string with a date in it (f.e. "2/13 2:09a") into a Date object which means that, from those functions, you need parse. Let's rewrite the array with this function:
const BlogTopic = [
{
title: "First Post",
message: "test",
author: "Dagger",
date: parse("2/13 2:09a", "M/dd h:mma", new Date()),
},
{
title: "Second Post",
message: "test",
author: "Dagger",
date: parse("2/13 3:48a", "M/dd h:mma", new Date()),
},
];
The benefit here is that, because parse returns a Date object, any operations we do afterwards (like the sorting itself) can be kept as they are since we haven't changed the expected data type.
Finally, for displaying the date, we need a function that will take a Date object and turn it into a string, this is the job of the format function:
BlogTopic.map(({ date }) => (
<tr><td>{format(date, "M/dd h:mma")}</td></tr>
)}
And there you have it! If you have been following all along, you should now have a code that works the way you expected.

Related

RangeError: Invalid Time Value after incorporating local storage

I'm working on a forum and using a form that the user fills out I'm storing data as an object inside an array. The data I'm storing includes the title of a topic, the message, the author and the date. That data is stored inside a topic array which I'm mapping on screen so the user can see all current topics, who created them and the date in which they were created. I also started to use localStorage so I can save my data and test to make sure everything looks good after my page refreshes.
const [topic, setTopic] = useState(() => {
const topicJson = localStorage.getItem("topic");
return topicJson ? JSON.parse(topicJson) : [];
});
const updatedTopic = [
...topic,
{
title: title,
message,
author: "Dagger",
date: new Date(),
},
];
setTopic(updatedTopic);
};
That's the code that I'm using which works as intended however when I map through the array to post the data on screen, I'm having trouble with showing the date. I'm using date-fns because it displays the date exactly how I want it.
Example: 2/19 9:39PM. That's how I want the date to look on screen and using date-fns has been the only thing I've found that makes it look that way.
{topic
.sort((a, b) => b.date - a.date)
.map(({ date }, index) => (
<tr>
{<td>{format(date, "M/dd h:mma")}</td>}
</tr>
))}
That's the code I'm using to map through the array to show the date. Before adding localStorage it worked fine. When I remove the format and show the code as date it works but including format gives me this error:
throw new RangeError('Invalid time value');
// Convert the date in system timezone to the same date in UTC+00:00 timezone.
// This ensures that when UTC functions will be implemented, locales will be compatible with them.
I think your are using Date object to store date and JSON.stringify cant handle Date object. You should to use Date method.
Easy way just save not Date object but ISO string.
date.toISOString()
And in table:
{<td>{format(parseISO(date), "M/dd h:mma")}</td>}

Why does this push not add a new field? (mongoDB)

I have a collection of restaurants where each document includes data such as the name, location, reviews, etc, and I'm attempting to push data which includes two reviews to the restaurant located in the borough of Brooklyn. This document happens to not currently have an array field of "reviews". According to everything I've looked at, the $push function should automatically add the array to the document, but it does not. Here is the code:
db.restaurants.updateOne(
{ borough: 'Brooklyn' },
{
$push: {
reviews: {
$each: [
{
name: 'Frank Zappa',
date: 'January 3, 2019',
rating: 3,
comments: 'This restaurant is not good',
},
{
name: 'Freddie Mercury',
date: 'January 3, 2019',
rating: 5,
comments: 'This restaurant is my favorite',
},
],
},
},
}
);
The next command after this is to push the same reviews to another restaurant that does already have the array field "reviews", and also slice to 2. The only difference in code between these two is the filter and the slice modifier. The second works perfectly, the first does not.
Am I misunderstanding how push should work? Using push is a requirement in this case, though I did also try addToSet with the same
https://mongoplayground.net/p/MxH01R4dxjU
it seems your Query is working fine plz check that you provided right values in the filter operation
Turns out I didn't pay close enough attention to how many documents have the "borough" : "Brooklyn" field and there was more than one. Changed to updateMany and the problem was solved. Thanks for the time and attention!

How can you filter out data based on their id?

So i kinda have to filter out my username from the given data so that you'll find the username that matches with the post but i don't really understand the role of the "[0]". Can anybody expain for me? Thank you so much!
This is my js:
<span className="postUsername">
{Users.filter((u) => u.id === post?.userId)[0].username}
</span>
This is my data:
export const Users = [{
id: 1,
profilePicture: "assets/person/1.jpeg",
username: "Safak Kocaoglu",
}
...
export const Posts = [{
id: 1,
desc: "Love For All, Hatred For None.",
photo: "assets/post/1.jpeg",
date: "5 mins ago",
userId: 1,
like: 32,
comment: 9,
}
...
First of all, in that case you are expecting to get a single user and show the username which is the post userId. Filter will return you an array of the user matching the condition we gave. For the array here you are picking first element of that array with [0]. Here we want to have a single user so best way is to use find(), this will give us a single result.
If you want to have the username of the specific user (post.userId), the code will be like this:
{Users.find(u=> u.id === post?.userId).username}
So, filter() function is used for getting array result of matching condition and here with [0] you are picking the first element of the array. Instead of that if you use find() function you will get a single object.

Meteor inserting into a collection schema with array elements

Hi I created a SimpleSchema for a Mongo collection which has a variable number of sub-documents called measurables. Unfortunately it's been a while since I've done this and I can't remember how to insert into this type of schema! Can someone help me out?
The schema is as follows:
const ExerciseTemplates = new Mongo.Collection('ExerciseTemplates');
const ExerciseTemplateSchema = new SimpleSchema({
name: {
type: String,
label: 'name',
},
description: {
type: String,
label: 'description',
},
createdAt: {
type: Date,
label: 'date',
},
measurables: {
type: Array,
minCount: 1,
},
'measurables.$': Object,
'measurables.$.name': String,
'measurables.$.unit': String,
});
ExerciseTemplates.attachSchema(ExerciseTemplateSchema);
The method is:
Meteor.methods({
addNewExerciseTemplate(name, description, measurables) {
ExerciseTemplates.insert({
name,
description,
createdAt: new Date(),
measurables,
});
},
});
The data sent by my form for measurables is an array of objects.
The SimpleSchema docs seem to be out of date. If I use the example they show with measurables: type: [Object] for an array of objects. I get an error that the the type can't be an array and I should set it to Array.
Any suggestions would be awesome!!
Many thanks in advance!
edit:
The measurable variable contains the following data:
[{name: weight, unit: kg}]
With the schema above I get no error at all, it is silent as if it was successful, but when I check the db via CLI I have no collections. Am I doing something really stupid? When I create a new meteor app, it creates a Mongo db for me I assume - I'm not forgetting to actually create a db or something dumb?
Turns out I was stupid. The schema I posted was correct and works exactly as intended. The problem was that I defined my schema and method in a file in my imports directory, outside both client and server directories. This methods file was imported into the file with the form that calls the method, and therefore available on the client, but not imported into the server.
I guess that the method was being called on the client as a stub so I saw the console.log firing, but the method was not being called on the server therefore not hitting the db.
Good lesson for me regarding the new recommended file structure. Always import server side code in server/main.js!!! :D
Thanks for your help, thought I was going to go mad!

How to create DOM element for each object's property variation in an object array?

I'm a newbie at angularjs and facing a problem.
I'm using an angular calendar (not a creation of mine).
Passing an object array (events) is mandatory for using it's directive in my code.
In templates of this plugin I can "consume" this array of object.
My issue is located here.
The array (eventArray) is composed of object like this one:
currentEvent = {
_id: bookingArray[i]._id,
private: bookingArray[i].private,
space: space_name,
user: user,
isOwnBook: $scope.connected_user._id === user._id,
title: resource_title,
startTime: new Date( bookingArray[i].ts_start),
endTime: new Date( bookingArray[i].ts_end),
allDay: false,
deleted: false,
};
Let's say I log each currentEvent.title in the array, console would be like this:
RoomA RoomB RoomC RoomA RoomB RoomZ ...
I want to create a div each time the currentEvent.title is different.
<span ng-repeat="currentEvent in dt.eventArray">{{currentEvent.title}}</span>
This previous code should print only:
RoomA RoomB RoomC RoomZ
How should I proceed in order to obtain this behavior ?
Best regards !
I manage to find out a solution.
You need to install angular-filter first.
Then the code in the template is like this:
<span ng-repeat="(key, value) in dt.eventArray | groupBy: 'title'">{{key}}</span>
And finally you get as many span as title variation

Resources