How do I store likes / dislikes and ratings in mongoose / mongdb using node.js

I have a schema for an element and a user. I want the user to be able to like or dislike the item, and I also want to keep the rating association for both the item and the user.

var UserSchema = new Schema({ username : { type: String, required: true, index: { unique: true } , likes : [{ type: Schema.ObjectId, ref: 'Item'}] , dislikes : [{ type: Schema.ObjectId, ref: 'Item'}] , ratings: [???] }); var ItemSchema = new Schema({ name: { type: String}, , likes : [{ type: Schema.ObjectId, ref: 'User'}] , dislikes : [{ type: Schema.ObjectId, ref: 'User'}] , ratings: [???] }); 

The user saves the ref element, and the element saves the user link for likes / dislikes. I am not sure how to store ratings as an attribute, though, since I want the user and value to rate the element.

 item.ratings.forEach(function(rating){ <%= rating.user.username %> gave <%= item.name %> a <%= rating.value %>. }); 

I also want to get a list of products rated by the user along with a nominal value:

 user.ratings.forEach(function(rating){ <%= user.username %> has rated <%= rating.item.name %> and gave it a <%= rating.value %> }); 

What should my β€œrating” scheme look like? Can two values ​​be saved? user object identifier and rating value (integer) and a set of them?

Another problem that I see in my method is that mongoose does not yet support deep filling, so I will either have to use a module for it (https://github.com/JoshuaGross/mongoose-subpopulate), which is pretty much not checked or stores it in another way that will not have more than one level of nesting, so I can get my data using .populate ()

Any feedback is appreciated as I am new to noSQL and maybe I am breaking it too much.

+7
source share
2 answers

I would do as you said. I would use a rating scheme:

 var RatingSchema = new Schema({ , _user : { type: ObjectId, ref: 'User' } , _item : { type: ObjectId, ref: 'Item' } , value : Integer }); 

If you want to have access to ratings from a user’s scheme, you will need to add a hook so that any saved RatingSchema is added to user.ratings.

 var UserSchema = new Schema({ /* ... */ ratings: [{ type: Schema.ObjectId, ref: 'Rating'}] }); RatingSchema.post('save', function () { // push this.id to this._user.ratings // save this._user }); 

Regarding: "Another problem that I see in my method is that the mongoose does not yet support deep filling", if you do not want to use the hacked mongoose-subpopulate, I suggest that you reorganize the loading of your models into static methods. For example:

 UserSchema.statics.findByIdAndDeepPopulate = function (i, cb) { UserSchema.findOne(id) .exec(function(err, user) { if (err || !user) return cb(new Error('User not found')); if (user._ratings.length == 0) return cb(null, user); // Load and populate every ratings in user._ratings for(var i = 0; i < user._ratings.length; i++) { function(i) { RatingSchema .populate('_item') .exec(err, function(rating) { user._ratings[i] = rating; if (i == user._ratings.length) return cb(null, user); }); }(i); } }); } 

EDIT: Now that I'm thinking about it again, why not just save the ratings as an embedded document in UserSchema?

 var UserSchema = new Schema({ /* ... */ ratings: [ RatingSchema ] }); 

Then you can simply fill in this way:

 UserSchema.findOne(id) .populate('ratings._item') .exec(function(err, user) { if (err || !user) return next(new Error('User not found')); console.log(user.ratings); }); 
+6
source

You want to avoid double stitching because it means twice as much to support, and because Mongo does not support transactions, it creates the possibility of semi-linked data if you expect it to be connected twice. In doing so, I revise your circuits like this:

 var like = { itemid: { type: Schema.ObjectId, ref: 'Item'} , rating: Number }; var UserSchema = new Schema({ username : { type: String, required: true, index: { unique: true } , likes : [like] , dislikes : [like] }); UserSchema.index({ 'likes.itemid': 1 }); UserSchema.index({ 'dislikes.itemid': 1 }); var User = db.model('User', UserSchema); var ItemSchema = new Schema({ name: String }); var Item = db.model('Item', ItemSchema); 

You can add likes or dislikes by saying:

 var piano = new Item({name: 'Mason & Hamlin Baby Grand Piano' }); var Joe = new User({ username: 'Joe_Smith' }); Joe.likes.push({ itemid: piano._id, rating: 10 }); 

And when you want to find the things you like for the item:

 User.find({ 'likes.itemid': piano._id }, function(err, userLikes) { ... }); 

And if none of this seems right to you, you can create a third collection ...

 var UserSchema = new Schema({ username : { type: String, required: true, index: { unique: true } }); var User = db.model('User', UserSchema); var ItemSchema = new Schema({ name: String }); var Item = db.model('Item', ItemSchema); var LikesSchema = new Schema({ , userid: { type: Schema.ObjectId, ref: 'User'} , itemid: { type: Schema.ObjectId, ref: 'Item'} , rating: Number }); LikesSchema.index({ userid: 1, itemid: 1 }, { unique: true }); 

And in this case, it is probably easiest to make the rule that a positive rating is similar and a negative rating is not like.

+3
source

All Articles