Search code examples
mongodbmongoose

Using $or to get ratings average of the selected values, for example from 4 to 4.9 doesn't work


In my DB the ratingsAverage's type is Number. I want to implement filtering functionality depending on the ratings. For example, if the user selects 4, the result will be the ratings that fall within the range of 4 to 4.9. Selecting other ratings is possible too.

I'm struggling with the $or operator, it doesn't return anything from the DB and I don't know the reason, I've tried a lot but no luck.

I have a function called destructSearchParams which takes all the filter params, writes the query statement then passes the query into the API:

function destructSearchParams(searchParams) {
    let sortBy;

    if (searchParams.hasOwnProperty("sortBy")) {
      sortBy = searchParams.sortBy;
      delete searchParams.sortBy;
    }
  
    const filter = {};
    for (const [key, value] of Object.entries(searchParams)) {
      const valuesArray = value.split(',');
      let query;
      
      switch (key) {
        case "roaster":
          query = { $in: valuesArray};
          break;

        case "ratingsAverage":
          const ratings = valuesArray.map(value => {
            const minRating = Math.floor(Number(value));
            const maxRating = minRating + 1;
            return {ratingsAverage: { $gte: minRating, $lt: maxRating }};
          });
            query = {$or: ratings}
            console.log(query);
          break;

        default:
          query = { $regex: valuesArray.join('|')};  // Join with '|' to match any
          break;
      }
        
      filter[key] = query;
    }

    return {filter, sortBy};
}

the implementation of case "ratingsAverage" throws

CastError: Cast to number failed for value "[ { ratingsAverage: { '$gte': 4, '$lt': 5 } } ]" (type Array) at path "ratingsAverage"

stringValue: `"[ { ratingsAverage: { '$gte': 4, '$lt': 5 } } ]"`,
  messageFormat: undefined,
  kind: 'number',
  value: [ { ratingsAverage: [Object] } ],
  path: 'ratingsAverage',
  reason: null,
  valueType: 'Array'

Solution

  • After reading the MongoDB docs carefully again, I noticed that $or operator doesn't have a field name before it, any field should be specified inside it, this is the correct format:

    $or: [{ ratingsAverage: { $gte: 4, $lt: 5 } }, { ratingsAverage: { 
        $gte: 0, $lt: 3 } }]
    

    The way I'm implementing the function is correct, my small problem was setting the key in this line of code after the switch-case:

    filter[key] = query;
    

    In order to get around this, I've changed the const [key, value] to let [key, value] then, inside the case of ratingsAverage the code became:

    key = "$or";
    query = ratings;