Search code examples
node.jsmongodbmongoosemongodb-querymern

How to find Average of star Rating in mongoose


I have working on my final year college project On MERN stack. my problem is mentioned bellow please help me.

const Organization = mongoose.Schema({
    name: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true
    },
    current_rating: {
        type: Number,
        default: 0
    },
    rating: [{
        user: {
            type: 'ObjectId',
            ref:'user'   
        },
        user_name:String,
        experience: String,
        feedback: String,
        star: Number,
        date: {
            type: Date,
            default:Date.now
        }
     }]
  }); 

for example Organization collection will look like this

[
 {
  name: 'abc.com'
    email: '[email protected]'
    current_rating: 0,
    rating: [
    {
      user: new ObjectId("623cb8bec55d003c2d9dd3da"),
      user_name: 'rupesh',
      experience: 'very good',
      feedback: 'In publishing and graphic design, Lorem ipsum',
      star: 3.5,
      _id: new ObjectId("6267d9301c4ceac2d4e6956a"),
      date: 2022-04-26T11:36:16.656Z
    },
    {
      user: new ObjectId("623cb8bec55d003c2d9dd3da"),
      user_name: 'rupesh',
      experience: 'very good',
      feedback: 'In publishing and graphic design, Lorem ipsum',
      star: 4,
      _id: new ObjectId("6267d9d6e6296ebf5e289155"),
      date: 2022-04-26T11:39:02.918Z
    },
    {
      // some content
    },
    .
    .
    .
     //and many more rating for this organization

 },
 {
   // data for other organization
 }
]

i was trying this query but it is not working in mongoose

const updatedCurrentRating = await Organization.findOneAndUpdate({ _id: req.params.org_id }, {
            $set: { current_rating: { $avg: 'rating.$.star' } }
        }, {
            new: true,
            useFindAndModify: true
        });
        console.log(updatedCurrentRating);

AssertionError, which i am geting in this query

CastError: Cast to Number failed for value "{ '$avg': 'rating.$.star' }" (type Object) at path "current_rating"
    at model.Query.exec (D:\react\project For Inter\server\node_modules\mongoose\lib\query.js:4650:21)
    at model.Query.Query.then (D:\react\project For Inter\server\node_modules\mongoose\lib\query.js:4749:15)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:93:5) {
  messageFormat: undefined,
  stringValue: `"{ '$avg': 'rating.$.star' }"`,
  kind: 'Number',
  value: { '$avg': 'rating.$.star' },
  path: 'current_rating',
  reason: AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:
  
    assert.ok(!isNaN(val))
  
      at castNumber (D:\react\project For Inter\server\node_modules\mongoose\lib\cast\number.js:27:10)
      at SchemaNumber.cast (D:\react\project For Inter\server\node_modules\mongoose\lib\schema\number.js:380:12)
      at SchemaNumber.SchemaType.applySetters (D:\react\project For Inter\server\node_modules\mongoose\lib\schematype.js:1179:12)
      at SchemaNumber.SchemaType._castForQuery (D:\react\project For Inter\server\node_modules\mongoose\lib\schematype.js:1613:15)
      at SchemaNumber.castForQuery (D:\react\project For Inter\server\node_modules\mongoose\lib\schema\number.js:434:14)
      at SchemaNumber.SchemaType.castForQueryWrapper (D:\react\project For Inter\server\node_modules\mongoose\lib\schematype.js:1580:20)
      at castUpdateVal (D:\react\project For Inter\server\node_modules\mongoose\lib\helpers\query\castUpdate.js:527:19)
      at walkUpdatePath (D:\react\project For Inter\server\node_modules\mongoose\lib\helpers\query\castUpdate.js:260:22)
      at castUpdate (D:\react\project For Inter\server\node_modules\mongoose\lib\helpers\query\castUpdate.js:96:7)
      at model.Query._castUpdate (D:\react\project For Inter\server\node_modules\mongoose\lib\query.js:4859:10) {
    generatedMessage: true,
    code: 'ERR_ASSERTION',
    actual: false,
    expected: true,
    operator: '=='
  },
  valueType: 'Object'
}

please tell me how i can get Average star for organization and store it into current_rating

Thank You.


Solution

  • $avg is an aggregate operator you cant use it on an normal update. But you can do a pipeline update like this (it has [ {$set ...]) Also you cant use the $.star on aggregation operators so the path is changed also.

    Playmongo

    const updatedCurrentRating = await Organization.findOneAndUpdate(
    { _id: req.params.org_id },
    [{$set: { current_rating: { $avg: 'rating.star' } }}],
    {
       new: true,
       useFindAndModify: true
    });
    
    console.log(updatedCurrentRating);