0

this question is related to the same problem exposed here (a solution has been added to that one) but I've re-designed my algorithm and I come to you with a quite different question.

What is this about ?

const mongoose = require('mongoose');
const sauceSchema = mongoose.Schema({
  userId: {type:String},
  name: {type:String, required:true},
  manufacturer:{type:String, required:true},
  description:{type:String, required:true},
  mainPepper: {type:String, required:true},
  imageUrl:{type:String, required:true},
  heat: {type:Number, required:true},
  likes: {type:Number},
  dislikes : {type:Number},
  usersLiked : {type:["String <userId>"]},
  usersDisliked: {type:["String <userId>"]},
});

module.exports = mongoose.model('sauce', sauceSchema);

the above model has, at the end, 2 arrays. Those two as mentioned, store userId's of people who liked or disliked a particular sauce product.

On the same model, just above the two arrays, we find two "counters" : likes and dislikes.

this model has been made with Mongoose and the collection of sauces is stored on MongoDB.

What is your problem ?

I have to make a route in my controllers for this like/dislike system and in order to do that I would like to access the two arrays length and set the numbered value of that length as the likes/dislikes value.

I read a dozen of posts, tried several options but either I'm sent back to an undefined, or I'm being said nothing.

What did you try so far ?

this is the route code with only the 'like' case for clarity purpose :

exports.likeSauce = (req,res,next) =>{  
  const liker = req.body.userId;
  let likeStatus = req.body.like;

  if(likeStatus === 1){
    sauce.updateOne({_id:req.params.id}, {$push:{usersLiked:liker}, $inc:{likes:totalLiked}})
      .then(()=>res.status(201).json({message:'you liked this sauce'}))
      .catch(error=>res.status(400).json({error}))
 }else{}

  • liker = id of the user who liked
  • likeStatus = a value sent by the front in a request and that can be 1(like) or 0(none) or -1(dislike).
  • usersLiked = the array of strings from the model that stores likers id's.
  • totalLiked = it would ideally be the usersLiked.length numbered value that would be passed as the likes 'counter' value and stored as a number in the data base.

For totalLiked, I tried various things as earlier mentioned but came down to two fairly similar lines :

let totalLiked = sauce.findOne([{$match:{_id:req.params.id}}, {$project:{usersLiked:{$size:'$usersLiked'}}}])
//or//
let totalLiked = sauce.aggregate([{$match:{_id:req.params.id,usersLiked:{$size:'$usersLiked'}}}])

One thing to mention about an element of the route:

   sauce.updateOne({_id:req.params.id}, {$push:{usersLiked:liker}, $inc:{likes:totalLiked}})

I got errors regarding the 'undefined' status of 'totalLiked', so I chose to put the $inc at the end of the pipeline in order to 'wait' for the liker to be added to the array in order to get a defined element that could return a workable length. But maybe I did mix things up here...

Thank you for reading my post and for any help you may be able to prove !

1 Answer 1

1

In my experience mongoose doesn't work very well with direct pipes. Instead they have their own method chains like these which have worked everytime

let totalLiked = await sauce.aggregate()
    .match({_id: req.params.id})
    .project({usersLiked: {$size: '$usersLiked'}})
Sign up to request clarification or add additional context in comments.

1 Comment

first of all, thanks for your answer. It did help show the arrays, yes. But sadly even if in the database, the said arrays are full, the console.log(totalLiked) does only return empty arrays, but I can do my own research on the matter

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.