Метеоритные стратегии публикации / подписки для уникальных коллекций на стороне клиента
Используя 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}})
}
})
Это кажется правдоподобным решением, но не оптимальным. Что если я захочу создать новую коллекцию на стороне клиента, состоящую из результатов поиска из нескольких коллекций на стороне сервера?
3 ответа
В общей зоне:
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 записей соответственно.
Я немного опоздал на вечеринку, но есть способ на самом деле иметь отдельные коллекции на клиенте для подмножеств одной коллекции серверов. В этом примере у меня есть коллекция серверов под названием 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/
Использовать публиковать-композитный пакет
// 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: []
});