Публикация документов в коллекции на метеорном клиенте в зависимости от наличия конкретного документа в другой коллекции (публикация с отношениями)
У меня две коллекции
- Предложения (соответствующие поля: _id)
- 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
,