Есть ли в приложении Meteor шаблон проектирования для обработки нескольких клиентов, вставляющих одну и ту же логическую запись «одновременно»?

В частности, у меня есть приложение типа скоринга, и несколько клиентов могут создать начальную, в основном пустую, запись Score для участника, когда он готов начать. Затем внешний вид записи используется, чтобы сделать ее доступной на странице для редактирования судьями, увеличения количества штрафов и т. Д.

Stages =  new Meteor.Collection("contests");
Entrants = new Meteor.Collection("entrants");
Scores = new Meteor.Collection("scores");

// official picks the next entrant 
Scores.insert( stage_id:xxxx, entrant_id:yyyy)

Я доволен последствиями разрешения конфликтов при редактировании записи Score, когда она попадает в Коллекцию. Я не знаю, как поступить с несколькими клиентами, пытающимися вставить Score для пары stage_id / entrant_id.

В синхронном приложении я бы предпочел использовать некоторую форму блокировки или ограничение ключа реляционной БД.

1
Mathew Boorman 29 Май 2013 в 16:41

1 ответ

Лучший ответ

Что ж, согласно этот ответ флаг Meteor $ upsert все еще находится в списке улучшений и, кажется, добавлен в стабильный ветка после выпуска 1.0.

Итак, первый способ - как было сказано добавить уникальный индекс:

Все способы реализации: перечислены здесь. Я бы рекомендовал вам использовать собственные индексы mongo, а не реализацию кода.

Оптимистичный способ параллелизма намного сложнее из-за отсутствия транзакций в MongoDB.

Вот моя реализация (будьте осторожны, может быть ошибка))):

var result_callback = function(_id) {
  // callback to call on successfull insert made
}

var $set = {stage_id: xxxx, entrant_id: xxxx};
var created_at = Date.now().toFixed();
var $insert = _.extend({}, $set, {created_at: created_at});
Scores.insert($insert, function(error, _id) {
  if (error) {
    //handle it
    return;
  }
  var entries = Scores.find($set, {sort: {created_at: -1}}).fetch()
  if (entries.length > 1) {
    var duplicates = entries.splice(0, entries.length - 1);
    var duplicate_ids = _.map(duplicates, function(entry) {
      return entry._id;
    });
    Scores.remove({_id: {$in: duplicate_ids}})
    Scores.update(entries[0]._id, $set, function(error) {
      if (error) {
        // handle it
      } else {
        result_callback(entries[0]._id)
      }
    })
  } else {
    result_callback(_id);
  }
});

Надеюсь, это даст вам несколько хороших идей)

К сожалению, предыдущая версия моего ответа была совершенно неверной.

1
Community 23 Май 2017 в 14:57
Эти связанные вопросы полезны. В основном я думал о том, что увидят клиенты. Сейчас я склоняюсь к предварительному созданию всех оценок для этапа, когда пользователь отмечает этап как «открытый». Это решает не только вышеперечисленное, но также позволяет избежать элементов списка реактивного оттока, которых нет в другой коллекции.
 – 
Mathew Boorman
1 Июн 2013 в 09:29
Думаю, предварительное создание было бы лучшим решением здесь. Намного проще. Намного более прозрачным.
 – 
icanhazbroccoli
3 Июн 2013 в 12:39