2013-11-27 4 views
1

Пусть следующий текущий случай:Сервера публикация стороны реактивной Метеор

  • У меня есть коллекция «Таблица»
  • таблица представляет собой объект со свойствами, как {частное: 0, PRIVATE1, private2, ...} (места 0,1,2 ...)
  • Публикация коллекции с двумя аргументами, одна из которых - вторая.
  • Учитывая место, публикация будет фильтровать (скрывать) свойства, которые клиент не может видеть.
  • Теперь таблицаID и место были взяты из сеанса клиента, поэтому все было реактивным.
  • У меня есть метод «takeSeat (seatNb)». Если клиент вызывает этот метод и ему разрешено сидеть за столом, номер места отправляется обратно клиенту, который затем помещает его в свою сессию под ключом сиденья. Это позволит обновить подписку и правильно фильтровать содержимое мест в таблице.

Я не доволен этим дизайном, потому что понял, что клиент может обманывать, подписываясь на сиденье сам по себе. Также (и что более важно) я использую другой клиент DDP в C++ и хотел бы сохранить эту логическую часть на стороне сервера. то есть не нужно подписываться с другим местом, как только я получу его, если я заберусь за стол, я бы хотел, чтобы сервер отображал правильные поля на столе сам по себе.

После нескольких поисков я решил добавить коллекцию в сторону «Игроков», чтобы я мог легко получить уведомление в моей коллекции «таблицы», и добавлен или удален «игрок» в таблицу. Но это только половина проблемы. Мне действительно нужно изменить обработчик самой публикации, чтобы фильтр стал реактивным. Вот где я застрял, вот несколько упрощенных кодов для понимания дела:

Meteor.publish("current-table", function(table_id) 
     { 
      var self = this; 

      var handle = Players.find({"tableID": table_id}).observeChanges(
        { 
         added: function(id) 
         { 
          console.log("A player joined the table added"); 
          self.changed("tables", table_id); 
         }, 
         removed: function(id) { 
          console.log("A player left the table"); 
          self.changed("tables", table_id); 
         } 
        }); 

      self.onStop(function() { 
       handle.stop(); 
      }); 

      // PUBLISH THE TABLE BUT HIDE SOME FIELDS BEFORE 
       var player = Players.findOne({"userID": this.userId, "tableID": table_id}) || {"seat": -1}; 
       var seat = player.seat; 

       var privateFilter = {"private0": false, "private1": false, "private2": false, "private3": false}; 
       delete privateFilter["private" + seat]; 
       return Tables.find(table_id, {fields: privateFilter}); 
     }); 

Как действовать? Есть ли более элегантный способ достичь этого?

ответ

1

Благодаря ответу от jrullmann я решил сделать специальную отфильтрованную публикацию, используя реактивность 2 коллекций.Вот мой окончательный код:

Meteor.publish("current-table", function(table_id) 
     { 
      var self = this; 

      function getFilteredTable() 
      { 
       var player = Players.findOne({"userID": self.userId, "tableID": table_id}) || {"seat": -1}; 
       var seat = player.seat; 
       var privateFilter = {"prv": false, "prv0": false, "prv1": false, "prv2": false, "prv3": false}; 
       delete privateFilter["prv" + seat]; 
       return Tables.findOne(table_id, {fields: privateFilter}); 
      } 

      var tableHandler = Tables.find(table_id).observeChanges(
        { 
         added: function() 
         { 
          self.added('tables', table_id, getFilteredTable()); 
         }, 
         removed: function() 
         { 
          self.removed('tables', table_id); 
         }, 
         changed: function() 
         { 
          self.changed('tables', table_id, getFilteredTable()); 
         } 
        }); 
      self.ready(); 
      self.onStop(function() { 
       tableHandler.stop(); 
      }); 

      var handle = Players.find({"tableID": table_id}).observeChanges(
        { 
         added: function(collection, id, fields) 
         { 
          self.changed('tables', table_id, getFilteredTable()); 
          console.log("added"); 
         }, 
         removed: function(collection, id, fields) 
         { 
          // Little trick to avoid meteor use the former deleted (hidden) properties 
          self.removed('tables', table_id); 
          self.added('tables', table_id, getFilteredTable()); 
          console.log("removed"); 
         } 
        }); 

      self.onStop(function() { 
       handle.stop(); 
      }); 
     }); 
+0

Можете ли вы взглянуть на это так, я думаю, что моя проблема похожа на вашу, но я не уверен, как свести их вместе? http://stackoverflow.com/q/34479708/271873 –

+0

неважно, я это понял :) –

2

Вы можете сохранить сиденье в профиле пользователя. Тогда ваша публикация будет следить за изменениями в профиле пользователя и при необходимости корректировать их.

Например:

Meteor.publish("current-table", function() { 
    var self = this; 
    var getFilteredTableForSeat = function(seat_id) { 
    // Get the table for the given seat_id, filtering the fields as appropriate 
    }; 

    var handle = Meteor.users.find({_id: this.userId}).observeChanges({ 
    changed: function (id, fields) { 
     if(fields.profile) 
     self.changed("tables", 'current-table', getFilteredTableForSeat(fields.profile.seat_id)); 
    } 
    }); 

    self.added("tables", 'current-table', getFilteredTableForSeat(Meteor.users.findOne(this.userId).profile.seat_id)); 
    self.ready(); 

    self.onStop(function() { 
    handle.stop(); 
    }); 
}); 

Если изменения места пользователя, то текущий стол документ коллекции Таблицы будут обновлены.

Этот пример делает некоторые предположения, и потребует корректировки, если они не верны для вас:

  • Вы можете найти таблицу по заданному seat_id (если вы не можете, вы, возможно, потребуется хранить table id в профиле пользователя)
  • Принадлежность seat_id всегда принадлежит к одной и той же таблице (в противном случае вам нужно будет добавить измененный обработчик туда, где хранится эта информация)
  • Информация о таблице возвращена публикация не изменяется (если это так, вам нужно добавить измененный дескриптор в коллекцию Table, аналогично дескриптору пользователя)
+0

Совершенно, я получил вашу концепцию, чтобы адаптироваться к моему делу. Я действительно смог сделать что-то еще более тривиальное, большое спасибо за подсказку. –

-1

У меня была аналогичная проблема, и написал эти две атмосферы пакеты, которые решают эту проблему:

https://atmosphere.meteor.com/package/server-deps

https://atmosphere.meteor.com/package/reactive-publish

Установите второй пакет с метеоритом, используйте «Meteor.reactivePublish» вместо «Meteor.publish», и он автоматически обновится, когда будут изменены результаты любых запросов с опцией {«reactive»: true}.

В этом примере из файла readme будут опубликованы именно те элементы, которые может видеть команда пользователя, и будет обновляться при изменении пользователем команды или видимых элементов команды.

Meteor.reactivePublish(null, function() { 
    if (this.userId) { 
    var user = Meteor.users.findOne({_id: this.userId}, {reactive: true}); 
    if (user.team) { 
     var team = Collections.teams.findOne({_id: user.team}, {reactive: true}); 
     var visibleItems = _.compact(team.visibleItems); 
     return Collections.items.find({_id: {$in: visibleItems}}); 
    } 
    } 
}); 
+0

Оба пакета не имеют документации, и когда я попытался добавить их, сервер начал жаловаться на отсутствующий метод onStop. –

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