This is a standard problem of calling an asynchronous function within a loop.
Let's look at a simpler example first. Say I want a function that prints the value of i in a for loop, and I want it to run asynchronously:
for (i = 0; i < 5; i++) {
setTimeout(function() { console.log(i); }, 1);
}
Now this will actually only print out 5, 5 times. This is because the asynchronous function setTimeout returns after the loop has ended, and the value of i at the time that it executes is 5. If we want it to print out 0 - 4, then we need to do the following:
for (i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() { console.log(i); }, 1);
})(i);
}
Notice how the anonymous function takes in i as a parameter. This creates a closure that "saves" the value of i at the time it was called.
Now back to your problem:
covariance = covariance + u * v;
This occurs before your console.log(covariance) statement, meaning that your print statement actually is occurring after the calculation. That means that covariance really is equal to 0 at this point.
Your covariance variable is initialized to 0. So are u and v. 0 + 0 * 0 = 0. Okay, great: so if u and v aren't being set properly, at least the math checks out.
Let's go back to your loop:
while (rating.length>0){
currentMovie = rating.pop();
var u=currentMovie.value-avarageRatingU;
var v=0;
Rating.find({movieid:currentMovie.movieid, user:a}, function(err,ratings) {
if (err) throw err;
if(ratings.length>0){
v=ratings.pop().value-avarageRatingV;
standardV=standardV+Math.pow(v,2);
covariance =covariance+u*v;
...
Here, we can see that your asynchronous Rating.find callback is pulling the last known value of u, i.e. its value at the end of the while loop. There isn't really any reason for v to be defined outside of the Rating.find callback.
If you want the value of u for each loop, try wrapping it in an anonymous self-executing function to "save" the value, like so:
Rating.find({user: b}, function(err,rating) {
var covariance = 0;
var standardU = 0;
var standardV = 0;
var u = 0;
while (rating.length > 0){
console.log("the avarage rating u is:" + avarageRatingU)
console.log("the avarage rating v is:" + avarageRatingV)
currentMovie = rating.pop();
u = currentMovie.value - avarageRatingU;
standardU = standardU + Math.pow(u, 2);
(function(u) {
Rating.find({ movieid: currentMovie.movieid, user: a }, function(err, ratings) {
if (err) throw err;
if (ratings.length > 0) {
var v = ratings.pop().value - avarageRatingV;
standardV = standardV + Math.pow(v,2);
covariance = covariance + u * v;
console.log(covariance);
}
});
})(u);
}
console.log(covariance)
callback(null,covariance);
//sim = covariance/(Math.sqrt(standardU)*Math.sqrt(standardV));
});
I've also moved the declaration of u outside of your loop (declaring them inside is bad practice, since you're reinstantiating the variable each time). I moved the declaration of v inside the Rating.find callback, as it's not even being used outside of there.
asyncfunctions instead, you won't have awhileloop anymore.