11

アイテムとユーザーのスキーマがあります。ユーザーがアイテムを好きまたは嫌いにできるようにしたいのですが、ユーザーだけでなくアイテムにも評価の関連付けを保存したいと思います。

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

ユーザーはアイテム参照を保存し、アイテムは好き/嫌いのユーザー参照を保存します。ただし、ユーザーとユーザーがアイテムを評価した値の両方が必要なため、評価を属性として保存する方法がわかりません。

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

また、ユーザーが評価したアイテムのリストと評価値を取得したいと思います。

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

「評価」スキーマはどのようになりますか?2つの値を保存することは可能ですか?ユーザーオブジェクトIDと評価値(整数)とこれらのコレクションがありますか?

私の方法で見られるもう1つの問題は、マングースがまだディープポピュレートをサポートしていないことです。そのため、モジュール(https://github.com/JoshuaGross/mongoose-subpopulate)を使用する必要があります。 -.populate()を使用してデータを取得できるように、複数のレベルのネストがない別の方法でテストまたは保存します

私はnoSQLを初めて使用し、おそらくこれを複雑にしすぎているので、フィードバックをいただければ幸いです。

4

2 に答える 2

6

あなたが言ったように私はします。評価スキーマを使用します:

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

Userスキーマから評価にアクセスできるようにする場合は、フックを追加して、保存されているRatingSchemaが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
});

「私のメソッドで見られるもう1つの問題は、マングースがまだディープポピュレートをサポートしていないことです」に関して、マングースサブポピュレートハックを使用したくない場合は、モデルのロードを静的メソッドにリファクタリングすることをお勧めします。例えば:

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

編集:もう一度考えてみましょう。評価を埋め込みドキュメントとしてUserSchemaに保存してみませんか?

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

次に、次のように単純にデータを入力できます。

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

    console.log(user.ratings);
  });
于 2012-10-21T05:58:58.127 に答える
4

二重クロスリンクは、維持する必要がある量が2倍になることを意味し、Mongoはトランザクションをサポートしていないため、二重接続が予想されるときにデータが半分接続される可能性があるため、回避する必要があります。そうは言っても、私はあなたのスキーマを次のように再考します。

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

次のように言って、好き嫌いを追加できます。

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

そして、あなたがアイテムのいいねを調べたいとき:

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

そして、それがあなたにとって正しいと感じない場合は、代わりに3番目のコレクションを作成することができます...

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

そしてこの場合、正の評価は好きであり、負の評価は嫌いであるというルールを作るのがおそらく最も簡単です。

于 2012-10-21T07:40:46.410 に答える