Is it possible to make the average of all the values of a collection related to ObjectId?

1

I have these two collections:

  var wineSchema = new Schema({
  name:         { type: String }, //nombre del vino
  code:       { type:String},
  type:         {
                    type: String,
                    enum: ['Tinto','Rosado','Blanco']
                },
  winery:       { type: String }, //Viñedo
  grape_type:   { type: String }, //tipo de uva
  year:         { type: Number }, // añada
  alcohol:      { type: Number },  //grados de alcohol
  rates:  [{ type: Schema.ObjectId, ref: "Puntuacion" }],
  comentarios:  [{ type: Schema.ObjectId, ref: "Comentario" }],
});

var puntuacion = new Schema({
  usuario   : { type: Schema.ObjectId, ref: "Usuario" },
  usuName   : {type: String},
  vineName  : { type: String},
  puntuacion    : { type: Number}
});

It is possible to make the average of all the punctuation scores.puntuation of each wine. The idea is to first make a populate pair that shows me all the wines with their respective scores and after all these make an average of punctuation.puntuacion with aggregate ..

I do not know if it is possible to do it .. Any ideas?

    
asked by Adri Feria 17.03.2016 в 18:29
source

1 answer

1

The fact is that @Diego is right.

A couple of notes:

  • It is not generally good practice to make an array of scores in the wine model, because eventually one without space ends (remember that a document can not exceed the size determined by its BSON ), and this is not good if the wine will have ... 20,000 scores? Apart from all the above, it will be easier to make a aggregator from a model and not at the document level. In that case in the scoring model is where the reference to wine is made. Different from the comments, where as a general rule there are not many, but if they are, the same thing.
  • Normally, programming in only one language, combining English with Spanish is sometimes a bit strange. Also, use camelCase instead of snake_case , since good ... it's Javascript!

Now yes, let's start:

In the model file Wine

const mongoose = require('mongoose')
,     Schema   = mongoose.Schema;

let wineSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    code: {
        type: String,
        required: true
    },
    type: {
        type: String,
        enum: [ 'Tinto', 'Rosado', 'Blanco' ],
        required: true
    },
    winery: {
        type: String,
        required: true
    },
    grapeType: {
        type: String,
        required: true
    },
    year: {
        type: Number,
        required: true
    },
    alcohol: {
        type: Number,
        required: true
    },
    comments: [{
        type: Schema.Types.ObjectId,
        ref: 'Comment'
    }]
});

module.exports = new mongoose.model('Wine', wineSchema);

In the model file Rate

const mongoose = require('mongoose')
,     Schema   = mongoose.Schema
,     ObjectId = mongoose.Types.ObjectId;

let rateSchema = new Schema({
    user: {
        type: Schema.Types.ObjectId,
        ref: "User",
        required: true
    },
    wine: {
        type: Schema.Types.ObjectId,
        ref: "Wine",
        required: true
    },
    rate: {
        type: Number,
        required: true
    }
});

rateSchema.statics.avg = function(wineId){
    return new Promise((resolve, reject) => {
        this.aggregate([{
            $match: {
                wine: new ObjectId(wineId)
            }
        }, {
            $group: {
                _id: '$wine',
                rate: {
                    $avg: '$rate'
                }
            }
        }], (error, results) => {
            if(error) return reject(error);
            return resolve(results);
        });
    });
};

module.exports = mongoose.model('Rate', rateSchema);
    
answered by 17.04.2016 в 13:47