Создайте реактивную публикацию с дополнительными полями в каждом документе

Я хочу сделать публикацию с несколькими дополнительными полями, но я не хочу ни использовать Collection.aggregate и потерять обновления моей публикации при изменении коллекции (поэтому я не могу просто использовать self.added в этом тоже нет).

Я планирую использовать Cursor.observeChanges для того, чтобы достичь этого. У меня есть два основных ограничения:

  1. Я не хочу публиковать все поля документов
  2. Я хочу использовать некоторые из неопубликованных полей для создания новых. Например, у меня есть поле item где я храню массив item _Я бы. Я не хочу публиковать это, но я хочу опубликовать item_count поле с длиной моего поля массива

Вот и подход:

  1. Я планирую цепочку запросов на поиск. Я никогда не делал этого, поэтому мне интересно, если это возможно. Общая (упрощенная) структура запроса будет выглядеть следующим образом: http://jsfiddle.net/Billybobbonnet/1cgrqouj/ (я не могу получить код, правильно отображаемый здесь)

  2. Основываясь на примере подсчета в документации Meteor, я сохраняю свой запрос в переменной handle чтобы остановить уведомление об изменениях, если клиент отписался:

self.onStop(function () {
  handle.stop();
});
  1. Я добавляю флаг 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.

Другие вопросы по тегам