I currently have a Mongoose schema for Item
documents, which has a subdocument called linkedItems. The two are defined as follows:
const ItemSchema = new Schema({
description: { type: [String], required: true },
linkedItems: [linkedItemSchema],
});
const linkedItemSchema = new Schema({
_id: Schema.Types.ObjectId,
title: String,
score: Number,
currentNumberOfRatings: Number,
});
All linked items have a score
attribute which stores the strength of the relationship between the parent Item
document and each linkedItem
. I have a function updateLinkedItemRating
, which when passed a new rating, the parent item ID, and the linked item ID, is supposed to update the score of the linked item by averaging in the new score (currentNumberOfRatings
is the number of ratings that have thus far been averaged into the score). The following piece of code within updateLinkedItemRating
is supposed to update this score, based on documentation I found on Mongoose subdocuments. It correctly calculates the new score, however the DB is not updated properly and both err
and result
in the callback are logging as null. Any suggestions would be appreciated.
Item.findOne({ _id: parentItemId }, function(err, item) {
// Calculate new average score, this all works fine
const linkedItem = item.linkedItems.id(linkedItemId);
const currentTotalNumberOfRatings = linkedItem.currentNumberOfRatings;
const currentScore = linkedItem.score;
const newAverageNumerator = parseInt(currentScore) * parseInt(currentTotalNumberOfRatings) + parseInt(rating);
const newAverageDenominator = parseInt(currentTotalNumberOfRatings) + 1;
const newAverageScore = newAverageNumerator * 1.0 / newAverageDenominator;
console.log(newAverageScore); // This logs the proper number
//This does not update the DB as expected
Item.findOneAndUpdate(
{ _id: item._id, 'linkedItems._id': linkedItemId },
{
$set: {
'linkedItems.$.score': newAverageScore,
'linkedItems.$.currentNumberOfRatings': currentTotalNumberOfRatings + 1,
},
},
function (err, result) {
console.log(err); // Logs null
console.log(result); // Logs null
}
);
});
You shouldn't need the findOneAndUpdate, as you already have the linkedItem when you do
const linkedItem = item.linkedItems.id(linkedItemId);
So you could just set those properties and then use .save()
linkedItem.score = newAverageScore;
linkedItem.currentNumberOfRatings = currentTotalNumberOfRatings;
item.save(function(err, result){
console.log(err);
console.log(result);
});