'Can't sort items by createdAt
I'm following this tutorial for an E-commerce website and applying the Sort functionality.
I've compared my code to the source code and I don't think there's difference in the method that the tutorial uses so I'm a little confused right now.
Here is the instructor's source code
Problem Description:
Sorting the products by the
pricefield ascending & descending works. But somehow, it cannot sort thelatestandoldestproducts by thecreatedAtfield.If I do a
console.log(a.createdAt - b.createdAt), it would returnNaN.
- In MongoDB, all items have both the
createdAtandpricefields.
- If I do console log on
a.createdAtorb.createdAt, it returns thecreatedAtresult as in the item.
- If I console.log(filteredProducts), it returns all 5 objects that contains the same 5 items.
-> Question: How would we fix this problem or is there a better way to sort items based on created date in this case?
Below is my code:
Product Schema
const mongoose = require('mongoose')
const ProductSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
desc: {
type: String,
required: true,
},
img: {
type: String,
required: true,
},
categories: {
type: Array,
required: true,
},
size: {
type: Array,
},
color: {
type: Array,
},
price: {
type: Number,
required: true,
},
inStock: {
type: Boolean,
default: true
}
},
{ timestamps: true }
)
module.exports = mongoose.model("Product", ProductSchema)
Products.js
const Products = ({ category, filters, sort }) => {
const [products, setProducts] = useState([])
const [filteredProducts, setFilteredProducts] = useState([])
useEffect(() => {
category && setFilteredProducts(
products.filter(item =>
Object.entries(filters).every(([key, value]) =>
item[key].includes(value)
)
)
)
}, [category, filters, products])
// Sorting:
useEffect(() => {
// Sort by latest date:
if (sort === "latest") {
setFilteredProducts(prev =>
[...prev].sort((a, b) =>
a.createdAt - b.createdAt
// console.log(a.createdAt - b.createdAt) -> This returns "NaN"
)
)
} else if (sort === "asc") {
setFilteredProducts(prev =>
[...prev].sort((a, b) => a.price - b.price)
)
} else if (sort === "desc") {
setFilteredProducts(prev =>
[...prev].sort((a, b) => b.price - a.price)
)
} else {
// Sort by oldest date:
setFilteredProducts(prev =>
[...prev].sort((a, b) => b.createdAt - a.createdAt)
)
}
}, [sort])
return (
<Container>
<Title>Popular In Store</Title>
<ProductsWrapper>
{filteredProducts.map(item => (
<Product key={item.id} item={item} />
))}
</ProductsWrapper>
</Container>
);
}
Solution 1:[1]
The createdAt property is a non-number-like string, so attempting arithmetic operations on them will result in NaN.
console.log("2022-04-03T07:55:18.556Z" - "2022-04-12T07:55:18.556Z"); // NaN
Use String.prototype.localeCompare() to compare string values in a sort comparator.
console.log("2022-04-03T07:55:18.556Z".localeCompare("2022-04-12T07:55:18.556Z")); // -1
Example:
// Sorting:
useEffect(() => {
// Sort by latest date:
if (sort === "latest") {
setFilteredProducts(prev =>
[...prev].sort((a, b) => a.createdAt.localeCompare(b.createdAt)
))
} else if (sort === "asc") {
setFilteredProducts(prev =>
[...prev].sort((a, b) => a.price - b.price)
)
} else if (sort === "desc") {
setFilteredProducts(prev =>
[...prev].sort((a, b) => b.price - a.price)
)
} else {
// Sort by oldest date:
setFilteredProducts(prev =>
[...prev].sort((a, b) => b.createdAt.localeCompare(a.createdAt))
)
}
}, [sort]);
Note this only works when date strings use units in decreasing order of unit size, i.e. year, then month, then day, etc... So ensure your dates conform to this. If this is not practical then you'll need to resort to processing the date strings into DateTime objects and using other methods of comparison.
console.log(new Date("2022-04-03T07:55:18.556Z") - new Date("2022-04-12T07:55:18.556Z")); // -777600000
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |




