Публикация документов в коллекции на метеорном клиенте в зависимости от наличия конкретного документа в другой коллекции (публикация с отношениями)

У меня две коллекции

  1. Предложения (соответствующие поля: _id)
  2. ShareRelations (соответствующие поля: receiveId и offerId)

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

На самом деле, я делаю это с помощью вспомогательного массива (visibleOffers), который я заполняю с помощью цикла для каждого ShareRelations и позже использую этот массив на Offers.find как $ in.

Интересно, может ли это быть метеорным способом сделать это, или я мог бы сделать с меньшим и / или более красивым кодом?

Мой фактический код для публикации предложений следующий:

Meteor.publish('offersShared', function () {
  // check if the user is logged in
  if (this.userId) {
    // initialize helper array
    var visibleOffers = [];
    // initialize all shareRelations which the actual user is the receiver
    var shareRelations = ShareRelations.find({receiverId: this.userId});
    // check if such relations exist
    if (shareRelations.count()) {
      // loop trough all shareRelations and push the offerId to the array if the value isn't in the array actually
      shareRelations.forEach(function (shareRelation) {
        if (visibleOffers.indexOf(shareRelation.offerId) === -1) {
          visibleOffers.push(shareRelation.offerId);
        }
      });
    }
    // return offers which contain the _id in the array visibleOffers
    return Offers.find({_id:  { $in: visibleOffers } });
  } else {
    // return no offers if the user is not logged in
    return Offers.find(null);
  }
});

Кроме того, реальное решение имеет недостаток, заключающийся в том, что при создании новых отношений общего доступа коллекция предложений на клиенте не обновляется мгновенно с новым видимым предложением (читай: требуется перезагрузка страницы. Но я не уверен, если это В этом случае из-за этого метода публикации или из-за другого кода этот вопрос не является основным из-за этой проблемы).

3 ответа

Решение

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

Meteor.publish('offersShared', function() {
  return Meteor.publishWithRelations({
    handle: this,
    collection: ShareRelations,
    filter: {receiverId: this.userId},
    mappings: [{collection: Offers, key: 'offerId'}]
  });
});

Это должно реактивно публиковать все ShareRelations для пользователя и всех связанных Offers, Надеюсь, что опубликовать оба не будет проблемой.

PWR - довольно легальный пакет - некоторые из нас используют его в производстве, и Том Коулман способствует этому. Единственное, о чем я вас предупреждаю, это то, что на момент написания этой статьи в текущей версии атмосферы (v0.1.5) была ошибка, которая привела к довольно серьезной утечке памяти. Пока он не столкнется, см. Мой пост в блоге о том, как запустить обновленную локальную копию.

обновление 5/5/14:

В блоге Discover Meteor есть отличный пост о реактивных соединениях, который я настоятельно рекомендую прочитать.

Способ сделать это в соответствии с этим Вопросом, используя наблюдайте за (). Все еще пытаетесь выяснить, как заставить все это работать для моего примера, посмотрите Метеор, Отношения один-ко-многим и добавьте поле только в коллекцию на стороне клиента в публикации?

Вы можете использовать пакет реактивной публикации (я один из авторов):

Meteor.publish('offersShared', function () {
  // check if the user is logged in
  if (this.userId) {
    this.autorun(function (computation) {
      // initialize helper array
      var visibleOffers = [];
      // initialize all shareRelations which the actual user is the receiver
      var shareRelations = ShareRelations.find({receiverId: this.userId}, {fields: {offerId: 1}});
      // loop trough all shareRelations and push the offerId to the array if the value isn't in the array actually
      shareRelations.forEach(function (shareRelation) {
        if (visibleOffers.indexOf(shareRelation.offerId) === -1) {
          visibleOffers.push(shareRelation.offerId);
        }
      });
      // return offers which contain the _id in the array visibleOffers
      return Offers.find({_id:  { $in: visibleOffers } });
    });
  } else {
    // return no offers if the user is not logged in
    return Offers.find(null);
  }
});

Вы можете просто обернуть существующий нереактивный код в autorun и это начнет работать. Только будьте осторожны, чтобы быть точным, какие поля вы запрашиваете, потому что, если вы запрашиваете по всем полям, то autorun будет перезапущен при любом изменении поля ShareRelations, не просто offerId,

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