Meteor публикует/подписывает стратегии для уникальных коллекций на стороне клиента

Используя Meteor, мне интересно, как лучше обращаться с различными коллекциями на стороне клиента, которые используют одну и ту же коллекцию базы данных на стороне сервера. Рассмотрим следующий пример: у меня есть коллекция User, и на моей стороне клиента у меня есть список пользователей, которые являются друзьями, и у меня есть функция поиска, которая выполняет запрос во всей базе данных пользователей, возвращая список имен пользователей, которые соответствует запросу.

В методе публикации на стороне сервера у меня есть два запроса к одной коллекции, которые возвращают разные наборы документов. Должны ли эти данные входить в две отдельные коллекции на стороне клиента? Или все документы пользователя, соответствующие обоим запросам, попадают в одну коллекцию? Если последний, я бы дублировал код, используемый как для серверной, так и для клиентской стороны?

На сервере:

Meteor.publish('searchResults', function(query){
  var re = new RegExp(query, 'i')
  return Users.find({ 'name' : {$regex: re}})
})

На клиенте:

Session.set('searchQuery', null)

Meteor.autosubscribe(function(){
  Meteor.subscribe('searchResults', Session.get('searchQuery'))
})

Template.search.events = {
  'keyup #user-search' : function(e){
    Session.set('searchQuery', e.target.value)
  }
}

_.extend(Template.search, {

  searchResults: function() {
    var re = new RegExp(Session.get('searchQuery'), 'i')
    return Users.find({ 'name' : {$regex: re}})
  }
})

Это кажется правдоподобным решением, но не оптимальным. Что делать, если я хотел создать новую коллекцию на стороне клиента, состоящую из результатов поиска из нескольких коллекций на стороне сервера?

Ответ 1

В общей области:

function getSearchUsers(query) {
  var re = new RegExp(query, "i");
  return Users.find({name: {$regex: re}});
}

function getFriendUsers() {
  return Users.find({friend: true});    // or however you want this to work
}

На сервере:

Meteor.publish("searchUsers", getSearchUsers);
Meteor.publish("friendUsers", getFriendUsers);

На клиенте:

Template.search.onCreated(function () {
   var self = this;
   self.autorun(function () {
     self.subscribe("searchUsers", Session.get("searchQuery"));
   });
});

Template.friends.onCreated(function () {
  this.subscribe("friendUsers");
});

Template.search.helpers({
  searchResults: function () {
    return getSearchUsers(Session.get("searchQuery"));
  }
});

Template.friends.helpers({
  results: function () {
    return getFriendUsers();
  }
});

Ключевым выводом из этого является то, что происходит за кулисами, когда данные становится переданным по проводу, не очевидно. Метеор объединяется записи, которые были сопоставлены в различных запросах на сервере и отправили это вплоть до клиента. Затем клиент должен снова запустить тот же запрос, чтобы разделить их друг от друга.

Например, скажем, у вас есть 20 записей в сборе на стороне сервера. Затем у вас есть два публикует: первые матчи 5 записей, во втором - 6, из которых 2 тоже самое. Метеор отправит 9 записей. На клиенте вы запускаете точное те же запросы, которые вы выполняли на сервере, и вы должны получить 5 и 6 соответственно.

Ответ 2

Я немного опаздываю на вечеринку, но есть способ фактически иметь отдельные коллекции на клиенте для подмножеств одной серверной коллекции. В этом примере у меня есть серверный набор под названием entities, который содержит информацию о polygons и rectangles.
Общий код (папка lib):

// main collection (in this example only needed on the server
Entities = new Meteor.Collection('entities');
// partial collections
RectEntities = new Mongo.Collection('rectEntities');
PolyEntities = new Mongo.Collection('polyEntities');

Клиентский код:

// this will fill your collections with entries from the Entities collection
Meteor.subscribe('rectEntities');
Meteor.subscribe('polyEntities');

Помните, что имя подписки должно соответствовать имени публикации (но не самому имени самой коллекции)
Код сервера:

Meteor.publish('rectEntities', function(){
    Mongo.Collection._publishCursor( Entities.find({shapeType: 'rectangle'}), this, 'rectEntities'); 
    this.ready();
});

Meteor.publish('polyEntities', function(){
    Mongo.Collection._publishCursor( Entities.find({shapeType: 'polygon'}), this, 'polyEntities'); 
    this.ready();
});

Благодаря user728291 для гораздо более простого решения с помощью _publishCursor()!
Третий аргумент функции _publishCursor() - это имя вашей новой коллекции.
Источник: http://docs.meteor.com/#/full/publish_added

Ответ 3

использовать publish-composite пакет

// main collection
Entities = new Meteor.Collection('entities');

// partial collections only client side
RectEntities = new Mongo.Collection('rectEntities');
PolyEntities = new Mongo.Collection('polyEntities');

// server publish
Meteor.publishComposite("rectEntities", function(someParameter) {
    return {
            collectionName:'rectEntities',
            find: function() {
                return Entities.find({shapeType: 'rectangle'});
            },
            children: []
    }
});
Meteor.publishComposite("polyEntities", {
        collectionName:'polyEntities',
        find: function() {
            return Entities.find({shapeType: 'polygon'});
        },
        children: []
});

источник: http://braindump.io/meteor/2014/09/20/publishing-to-an-alternative-clientside-collection-in-meteor.html