- In MongoDB, all items have both the
createdAt
andprice
fields.
- If I do console log on
a.createdAt
orb.createdAt
, it returns thecreatedAt
result 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>
);
}
CodePudding user response:
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