2012-10-21 18 views
7

Mam schemat dla elementu i użytkownika. Chcę zezwolić użytkownikowi na polubienie lub nie podoba mi się przedmiot, a także chcę zapisać powiązanie ratingowe zarówno na przedmiocie, jak i na użytkowniku.Jak powinienem przechowywać oceny podobieństwa/negatywne i oceny w mangdb/mongdb przy użyciu pliku node.js

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: [???] 
}); 

Użytkownik przechowuje informację o przedmiocie, a przedmiot zapisuje wzorzec użytkownika pod kątem pozytywnych lub negatywnych ocen. Nie jestem pewien, jak przechowywać oceny jako atrybut, ponieważ chcę, aby zarówno użytkownik, jak i wartość, którą ocenili przedmiot.

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

Chcę również uzyskać listę elementów ocenianych przez użytkownika wraz z wartością ocena:

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

Jaki powinien być mój „oceny” schemat wyglądać? Czy można zapisać dwie wartości? identyfikator obiektu użytkownika i wartość oceny (liczba całkowita) i mieć ich kolekcję?

Innym problemem, który widzę z moją metodą jest to, że mangusta nie obsługuje jeszcze głębokiego zaludnienia, więc musiałbym albo użyć do tego modułu (https://github.com/JoshuaGross/mongoose-subpopulate), to w dużej mierze nie jest testowane lub przechowywane w inny sposób, który nie będzie miał więcej niż jeden poziom zagnieżdżania, więc mogę uzyskać moje dane za pomocą .populate()

Wszelkie opinie są mile widziane, ponieważ jestem nowy do noSQL i być może nadmiernie komplikuję to.

Odpowiedz

6

Zrobiłbym tak, jak powiedziałeś. Chciałbym użyć schematu Ocena:

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

Jeśli chcesz mieć dostęp do oceny ze schematu użytkownika, trzeba by dodać hak tak, że każda zapisana RatingSchema dodaje do 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 
}); 

Odnośnie „Inny problem widzę z mojej metody jest to, że mangusta nie obsługuje głębokie populate jeszcze”, jeśli nie chcesz używać hack Mongoose-subpopulate, proponuję byłaby załadunek swoich modeli w statyczne metody. Na przykład:

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: Teraz myślę o tym jeszcze raz, dlaczego nie po prostu przechowywać oceny jako dokument embed w UserSchema?

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

Mogłeś po prostu wypełnić ten sposób:

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

    console.log(user.ratings); 
    }); 
+0

Nie sądzę, że możesz zrobić to jeszcze w mangurze: '.populate ('ratings._item')' - to właśnie mam na myśli przez deep populate(). – chovy

+0

Tak, możesz to zrobić, jeśli oceny są dokumentem osadzonym, a nie ref. Wykonuję to dokładne połączenie w moim własnym kodzie. (z różnymi nazwami oczywiście) –

+0

Jeśli używam ocen: [RatingSchema] - w jaki sposób mogę go wypełnić? Co wkładam do tablicy ocen? Chcę mieć osobną tablicę ocen - nie sądzę, że chcę osadzać i tracić ocenę w obiekcie użytkownika, którego nie mogę wyszukać. W końcu chcę zrobić Ratings.find ({_ item: item._id}, fn); – chovy

3

chcesz uniknąć podwójnego sieciowania, ponieważ to oznacza, że ​​jest dwa razy tyle, aby utrzymać i dlatego Mongo nie obsługuje transakcji tworzy możliwość połowicznego połączenia danych, gdy oczekuje się, że będzie on podwójnie połączony.Powiedział, że jest mi przemyśleć swoje schematy tak:

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); 

Możesz dodać sympatie lub antypatie, mówiąc:

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 }); 

A kiedy chcesz spojrzeć lubi za przedmiot:

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

A jeśli nic z tego nie jest w porządku, możesz zamiast tego stworzyć trzecią kolekcję ...

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 }); 

W tym przypadku najprawdopodobniej najłatwiej jest wprowadzić zasadę, że pozytywna ocena jest podobna, a negatywna to niechęć.