2014-12-16 5 views
0

Я пытаюсь внедрить систему оценки, и я изо всех сил пытаюсь разрешить только один рейтинг для каждого пользователя.Простой способ разрешить только один элемент для каждого пользователя в массиве схемы mongoose

Проще говоря, у меня есть массив оценок в моей схеме, содержащий «рейтер» и рейтинг, как таковой:

var schema = new Schema({ 
//... 
    ratings: [{ 
     by: { 
      type: Schema.Types.ObjectId 
     }, 
     rating: { 
      type: Number, 
      min: 1, 
      max: 5, 
      validate: ratingValidator 
     } 
    }], 
//... 
}); 

var Model = mongoose.model('Model', schema); 

Когда я получаю запрос, я хотел бы добавить рейтинг пользователей к массив, если пользователь еще не проголосовал за этот документ, в противном случае я хочу обновить рейтинг (вы не сможете дать более одного рейтинга)

Один из способов сделать это - найти документ, «массив рейтингов и поиск пользователя. Если у пользователя уже есть рейтинг в массиве, рейтинг меняется, иначе новый рейтинг будет нажат. Таким образом:

Model.findById(id) 
    .select('ratings') 
    .exec(function(err, doc) { 
     if(err) return next(err); 

     if(doc) { 
      var rated = false; 
      var ratings = doc.ratings; 
      for(var i = 0; i < ratings.length; i++) { 
       if(ratings[i].by === user.id) { 
        ratings[i].rating = rating; 
        rated = true; 
        break; 
       } 
      } 

      if(!rated) { 
       ratings.push({ 
        by: user.id, 
        rating: rating 
       }); 
      } 

      doc.markModified('ratings'); 
      doc.save(); 
     } else { 
      //Not found 
     } 
    }); 

Есть ли более простой способ? Способ позволить mongodb делать это автоматически?

Оператор mongodb $addToSet может быть альтернативой, однако мне не удалось использовать его для этого, поскольку это может позволить двум рейтингам с разными баллы от одного и того же пользователя.

ответ

0

Как вы отмечаете оператор $addToSet не будет работать в этом случае, как, впрочем идент с другим значением голосования будет другое значение и собственный уникальный элемент набора.

Таким образом, лучший способ сделать это - фактически выдать два операторы обновления с дополнительной логикой. В зависимости от состояния документа фактически применяется только один:

async.series(
    [ 
     // Try to update a matching element 
     function(callback) { 
      Model.update(
       { "_id": id, "ratings.by": user.id }, 
       { "$set": { "ratings.$.rating": rating } }, 
       callback 
      ); 
     }, 
     // Add the element where it does not exist 
     function(callback) { 
      Model.update(
       { "_id": id, "ratings.by": { "$ne": user.id } }, 
       { "$push": { "ratings": { "by": user.id, "rating": rating } }}, 
       callback 
      ); 
     } 
    ], 
    function(err,result) { 
     // all done 
    } 

);

Принцип прост, попробуйте сопоставить userId, присутствующий в массиве оценок для документа, и обновите запись. Если это условие не выполняется, документ не обновляется. Точно так же попробуйте сопоставить документ, в котором нет атрибута userId в массиве оценок, если есть совпадение, затем добавьте элемент, иначе обновление не будет.

Это обходит встроенную схему проверки мангуста, поэтому вам придется применять свои ограничения вручную (или проверить правила проверки схемы и применять вручную), но это лучше, чем ваш текущий подход в одном очень важном аспекте.

Когда вы .find() документа и перезвоните его в свое клиентское приложение, чтобы изменить его с помощью кода, как вы, то нет гарантии, что документ не изменился на сервере с другого процесса или запроса. Поэтому, когда вы выдаете , документ на сервере может больше не находиться в состоянии, когда оно было прочитано, и любые изменения могут перезаписать сделанные там изменения.

Следовательно, хотя на сервере есть две операции, а не одна (и ваш текущий код - это две операции), это означает, что меньшее из двух зол проверяется вручную, чем может привести к несогласованности данных. Два подхода к обновлению будут уважать любые другие обновления, выпущенные для документа, возможно, возникающие в одно и то же время.

+0

Спасибо, это здорово. Гораздо лучше, чем мое предложение. – johnrapp

Смежные вопросы