简体   繁体   中英

Creating a relationship between models with additional info in Mongo, Express, Node

somewhat new to Node and been struggling with this model relationship and not finding an answer here.

I have four models I'm trying to create relationships between:

  1. User
  2. Review
  3. Topics
  4. Courses

When a User leaves a Review on a Course in a certain Topic, I want to track a "topic score" on the User model.

So if a User Reviewed a programming Course, they should get +10 to their programming Topic score. Then I should be able to query User.scores.programming to get their Programming score.

The Reviews are being created fine, it's just the Topic scoring part where I'm running into issues.

Here's how my User schema are set up, just the relevant part:

const userSchema = new mongoose.Schema({
...
  scores: [{
    topic: {
      type: mongoose.Schema.ObjectId,
      ref: 'Topic'
    },
    score: {
      type: Number,
      default: 0
    }
  }]
});

And here's the code I have so far right now for trying to increment the score:

const updateUserScores = async (userId, course) => {
  const user = await User.findOne({_id: userId}).populate('scores');
  const userScores = user.scores;
  let topics = await Course.findOne({_id: course}).populate('tags');
  topics = topics.tags.map(x => x._id);
  // I know it works for here to get the array of topics that they need to be scored on
  
  // Then we need to go through each topic ID, see if they have a score for it...
  // If they do, add 10 to that score. If not, add it and set it to 10
  
  for (topic in topics) {
    const operator = userScores.includes(topic) ? true : false;
    if (!operator) {
      // Add it to the set, this is not currently working right
      const userScoring = await User
        .findByIdAndUpdate(userId, 
            { $addToSet: { scores: [topic, 10] }},
            { new: true}
        )
    } else {
      // Get the score value, add 10 to it
      
    }
  }
}

I know I probably have a few different things wrong here, and I've been very stuck on making progress. Any pointers or examples I can look at would be extremely helpful!

Alright so after lots of messing around I eventually figured it out.

User model stayed the same:

scores: [{
topic: {
  type: mongoose.Schema.ObjectId,
  ref: 'Tag'
},
score: {
  type: Number,
  default: 0
}

}]

Then for the code to increment their score on each topic when they leave a review:

const updateUserScores = async (userId, course) => {
  const user = await User.findOne({_id: userId}).populate({
    path    : 'scores',
    populate: [
        { path: 'topic' }
    ]
  });
  let userScores = user.scores;
  userScores = userScores.map(x => x.topic._id);
  let topics = await Course.findOne({_id: course}).populate('tags');
  topics = topics.tags.map(x => x._id);
  for (t of topics) {
    const operator = userScores.includes(t) ? true : false;
    if (!operator) {
      const userScoring = await User
        .findByIdAndUpdate(userId, 
            { $addToSet: { scores: {topic: t, score: 10}}},
            { new: true}
        );
    } else {
      const currentScore = await user.scores.find(o => o.topic._id == `${t}`);
      
      const userScoring = await User
        .findByIdAndUpdate(userId,
          { $pull: { scores: {_id: currentScore._id}}},
          { new: true }
        )
      const userReScoring = await User
        .findByIdAndUpdate(userId,
          { $addToSet: { scores: {topic: t, score: (currentScore.score + 10)}}},
          { new: true }
        )
    }
  }
}

Ugly and not super elegant, but it gets the job done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM