Создайте реактивную публикацию с дополнительными полями в каждом документе
Я хочу сделать публикацию с несколькими дополнительными полями, но я не хочу ни использовать Collection.aggregate
и потерять обновления моей публикации при изменении коллекции (поэтому я не могу просто использовать self.added
в этом тоже нет).
Я планирую использовать Cursor.observeChanges
для того, чтобы достичь этого. У меня есть два основных ограничения:
- Я не хочу публиковать все поля документов
- Я хочу использовать некоторые из неопубликованных полей для создания новых. Например, у меня есть поле
item
где я храню массивitem
_Я бы. Я не хочу публиковать это, но я хочу опубликоватьitem_count
поле с длиной моего поля массива
Вот и подход:
Я планирую цепочку запросов на поиск. Я никогда не делал этого, поэтому мне интересно, если это возможно. Общая (упрощенная) структура запроса будет выглядеть следующим образом: http://jsfiddle.net/Billybobbonnet/1cgrqouj/ (я не могу получить код, правильно отображаемый здесь)
Основываясь на примере подсчета в документации Meteor, я сохраняю свой запрос в переменной
handle
чтобы остановить уведомление об изменениях, если клиент отписался:
self.onStop(function () {
handle.stop();
});
- Я добавляю флаг
initializing = true;
перед моим запросом, и я установил егоtrue
как раз перед звонкомself.ready();
, Я использую этот флаг, чтобы изменить мойitemCount
переменная только в том случае, если это публикация инициализирована. Так что в основном я меняюswitch
как это:
switch (field) {
case "item"
if (!initializing)
itemCount = raw_document.item.length;
break;
default:
}
Я хотел убедиться, что этот подход хорош и возможен, прежде чем вносить большие изменения в мой код. Может ли кто-нибудь подтвердить мне, если это правильный путь?
2 ответа
Относительно легко сохранять приватность полей, даже если они являются частью запроса к базе данных. Последний аргумент self.added
это объект, который передается клиенту, поэтому вы можете удалить / изменить / удалить поля, отправляемые клиенту.
Вот модифицированная версия вашей скрипки. Это должно сделать то, что вы просите. (Если честно, я не уверен, почему у вас было что-то приковано после observeChanges
функционировать в вашей скрипке, так что, возможно, я вас неправильно понимаю, но, глядя на остальную часть вашего вопроса, это должно быть. Извините, если я ошибся.)
var self = this;
// Modify the document we are sending to the client.
function filter(doc) {
var length = doc.item.length;
// White list the fields you want to publish.
var docToPublish = _.pick(doc, [
'someOtherField'
]);
// Add your custom fields.
docToPublish.itemLength = length;
return docToPublish;
}
var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}})
// Use observe since it gives us the the old and new document when something is changing.
// If this becomes a performance issue then consider using observeChanges,
// but its usually a lot simpler to use observe in cases like this.
.observe({
added: function(doc) {
self.added("myCollection", doc._id, filter(doc));
},
changed: function(newDocument, oldDocument)
// When the item count is changing, send update to client.
if (newDocument.item.length !== oldDocument.item.length)
self.changed("myCollection", newDocument._id, filter(newDocument));
},
removed: function(doc) {
self.removed("myCollection", doc._id);
});
self.ready();
self.onStop(function () {
handle.stop();
});
Чтобы решить вашу первую проблему, вам нужно указать MongoDB, какие поля он должен возвращать в курсоре. Оставьте поля, которые вам не нужны:
MyCollection.find({}, {fields: {'a_field':1}});
Решение вашей второй проблемы также довольно легко, я бы предложил использовать пакеты помощников по сбору. Вы можете сделать это легко, например, так:
// Add calculated fields to MyCollection.
MyCollection.helpers({
item_count: function() {
return this.items.length;
}
});
Это будет выполнено до того, как объект будет добавлен в курсор, и создаст свойства для возвращаемых объектов, которые рассчитываются динамически, а не хранятся в MongoDB.