Home > other >  Can't sort items by createdAt
Can't sort items by createdAt

Time:04-08

I'm following enter image description here

  • In MongoDB, all items have both the createdAt and price fields.

enter image description here

  • If I do console log on a.createdAt or b.createdAt, it returns the createdAt result as in the item.

enter image description here

  • If I console.log(filteredProducts), it returns all 5 objects that contains the same 5 items.

enter image description here

-> 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

  • Related