Client Reactive Join in Meteor

Encontrei esse problema ao tentar criar um recurso de blog simples no Meteor, onde tenho 2 coleções relacionadas entre si. Um é chamado newse o outro é chamado images. Cada notícia terá uma imageIdreferência à imagem a ela associada. Usei o CollectionFS para a imagescoleção.

No começo fiz uma maneira ingênua de publicar a notícia com a imagem. Onde eu consultar a lista de imageIdsdo newse retornar Imagescorrespondente a esses ids. Aqui está o meu código:

Meteor.publish('newsWithImage', function(options) {
if (options) check(options, { limit: Number });
else options = { limit: 5 };
options
.sort = { createdAt: -1 };
var news = News.find({}, options);
var imageIds = news.map( function(news) { return news.image_id });
// Naive join
// if image is updated, news won't update the new image until reload.
return [
news
,
Images.find({_id: {$in: imageIds}})
];
});

O problema é que, sempre que carrego uma nova postagem, apenas a newscoleção no cliente recebe a atualização, enquanto a imagem permanece inalterada. Como resultado, a nova postagem apareceria com um espaço vazio onde a imagem pertence. Isso acontece porque o método de publicação no servidor não é reativo e não recalcula imageIdsquando a notícia muda.

A solução é calcular o imageIdsno cliente, de modo que sempre que o imageIdsarray mudar, a assinatura da imagem seja atualizada.

Então, divido a publicação em dois métodos; um para o newse outro para imagescom uma matriz de ids como parâmetro.

No servidor:

 // server/publications.js
Meteor.publish('news', function(options) {
if (options) check(options, { limit: Number });
else options = { limit: 5 };
options
.sort = { createdAt: -1 };
var news = News.find({}, options);
return news;
});

Meteor.publish('imageWithIds', function(imageIds) {
return Images.find({_id: {$in: imageIds}});
});

No cliente:

Template.newsList.onCreated(function () {
var instance = this;
// autorun for news
instance
.autorun( function (){
//Some setup code ...
instance
.subscribe('news', options);
});
// autorun for images
instance
.autorun( function() {
var imageIds = News.find().map( function(p){ return p.image_id });
console
.log(imageIds);
instance
.subscribe('imageWithIds', imageIds);
});
});

Aqui, estou fazendo a assinatura em nível de modelo (você pode aprender mais sobre isso aqui ). é semelhante a , exceto que também é específico para este modelo. O que o autorun faz é reexecutar a função que você passa para ele toda vez que os dados dentro da função mudam.instance.autorunTracker.autorun

Portanto, ao inserir uma nova notícia, a imageIdsexecução automática da imagem mudaria (aumentaria em um valor). Isso faria com que a função dentro da execução automática fosse executada novamente e a assinatura da imagem fosse atualizada.

* Note que a assinatura da publicação de ‘notícias’ provavelmente não precisa estar dentro do método autorun no caso normal, mas aqui meus optionsparâmetros são reativos, então eu quero atualizar a assinatura sempre que optionsmudar.

Se você deseja obter uma visão geral mais completa de ingressar em coleções de forma reativa, consulte o artigo de Sasha Grief em Discover Meteor.