2015-03-28 4 views
4

У меня есть следующие модели:Mongoose/Экспресс: среднее поддокументов

продукт:

var ProductSchema = new Schema({ 
name: String, 
comments: [{ type: Schema.Types.ObjectId, ref: 'Comment'}], 
_user: { type: Schema.Types.ObjectId, ref: 'User'} 
}); 

Комментарий:

var CommentSchema = new Schema({ 
text: String, 
rating: Number, 
_product: { type: Schema.Types.ObjectId, ref: 'Product'} 
}); 

Что я в настоящее время получить все продукты вместе с их пользователем :

router.get('/', function(req, res, next) { 
Product.find().populate('_user').exec(function (err, products) { 
    if (err) return next(err); 
    res.json(products); 
}); 
}); 

Я хотел бы добавить к результатам «среднее» поле, которое содержит среднее значение всех комментариев для каждого продукта, так что результаты будут выглядеть следующим образом:

[{name: "Product 1", _user: {name: "Bob"}, average: 7.65},...] 

Возможно ли это с уникальным запросом? Нужно ли мне вычислять и хранить среднее значение в документе Product каждый раз, когда добавляется новый комментарий?

Спасибо!

+0

Have A посмотрите на виртуальные поля Mongoose: http://mongoosejs.com/docs/guide.html – ZeMoon

ответ

1

Возможно, вам стоит попробовать вычислить значение «Бегущее среднее». Вам нужно только знать, сколько рейтингов есть, и каково их среднее. Наличие одинакового среднего значения для каждого документа в MongoDB должно быть плохой практикой, я надеюсь, что это поможет вам. Таким образом, вы можете создать схему, как это:

var AverageProductRatingSchema = new Schema({ 
    productId:  {type: Schema.Types.ObjectId, ref: 'Product'}, 
    averageRating: {type: Number}, 
    numberOfRatings: {type: Number} 
}); 

Тогда просто реализовать addRating() функция что-то вроде этого:

function addRating(newRating, productId) { 
    /* Find document that holds average rating of wanted product */ 
    AverageProductRating.findOneAsync({productId: productId}) 
    .then(function (avgProdRating) { 

     /* 
     Calculate new average using the Running Average method. 
     http://www.bennadel.com/blog/1627-create-a-running-average-without-storing-individual-values.htm 
     */ 
     var newAverageRating = (avgProdRating.averageRating * avgProdRating.numberOfRatings + newRating)/(avgProdRating.numberOfRatings + 1); 
     var newNumberOfRatings = avgProdRating.numberOfRatings + 1; 

     AverageProductRating.update(
     { productId: productId }, 
     { 
      $set: { 
      averageRating: newAverageRating, 
      numberOfRatings: newNumberOfRatings 
     } 
     }); 
    }); 

} 

Это ссылка, которая описывает похожую проблему: http://www.bennadel.com/blog/1627-create-a-running-average-without-storing-individual-values.htm

+0

Почему вы говорите, что одинаковое среднее значение сохраняется для каждого документа? Каждый продукт имеет среднее значение для всех своих обзоров. Среднее значение хранится внутри документа Product и только пересчитывается при добавлении, изменении или удалении новых отзывов. – Komo

+0

Возможно, у нас есть немного недоразумений. Я хотел бы помочь вам, поэтому вам не нужно просматривать все комментарии, вычисляя новый рейтинг. Вы добавляете только рейтинг от нового комментария и делаете простой расчет. Теперь представьте, что у вас есть тысячи комментариев с оценками на каком-то продукте. Каждый раз, когда вам нужен средний рейтинг, вам нужно будет запросить БД для всех комментариев и рассчитать среднее значение. Этот алгоритм «работающего среднего» должен предотвратить это. Конечно, вы можете сохранить средний рейтинг, хранящийся в коллекции документов продукта, который у вас уже есть. – Drag0

+0

О, я понимаю, что вы имеете в виду сейчас, это имеет смысл. Благодаря ! – Komo

Смежные вопросы