1

I'm using meteor and I have a question about the publish function (server side)

Meteor.publish('users', function () { .... }

I'm sending now documents to the browser which have id's of other collections. For example the Task document belongs to a project

{ 
    title: '....',
    projectId: 'KjbJHvJCHTCJGVY234',
    ...
}

What I want is to add a property to the this document projectTitle so I don't have to look up the project on the client. However, when I add this property in the publish function it is not send to the client. This is what I've tried:

Meteor.publish('tasks', function () {
    var tasks = Tasks.find();

    tasks.forEach(function (task) {
       var project = Projects.findOne({_id: task.projectId});
       task.projectTitle = project.title;
    });

    return tasks;
}

Any suggestions how to modify documents (not persistent) inside the publish function?

user247702
  • 23,641
  • 15
  • 110
  • 157
Jeanluca Scaljeri
  • 26,343
  • 56
  • 205
  • 333

2 Answers2

2

You could do this:

Meteor.publish("tasks", function() {

    var transform = function(task) {
        var project = Projects.findOne({_id: task.projectId});
        task.projectTitle = project.title;
        return task;
    }

    var self = this;

    var tasks = Tasks.find().observe({
        added: function (document) {
            self.added('tasks', document._id, transform(document));
        },
        changed: function (newDocument, oldDocument) {
            self.changed('tasks', document._id, transform(newDocument));
        },
        removed: function (oldDocument) {
            self.removed('tasks', oldDocument._id);
        }
    });

    self.ready();

    self.onStop(function () {
        tasks.stop();
    });

});

There's a lot of custom logic there, but the 'transform' basically adds the attributes in.

Tarang
  • 75,157
  • 39
  • 215
  • 276
  • Wow, this did the trick. Why isn't there a return value ? Is this somewhere documented ? I like to read more about whats going on here! – Jeanluca Scaljeri May 28 '14 at 20:40
  • It should be noted that you don't get reactivity with this solution. If the project's title is changed, the tasks title will be the old project's title. – Peppe L-G May 29 '14 at 06:52
  • @PeppeL-G you can add reactivity by observing the projects in a way similar to the link you posted in the other answer, but if it is for a query like Tasks.find(), like the reactive publish it will consume a very large number of resources to observe each one – Tarang May 29 '14 at 07:11
0

Your code looks good but you're forgetting the .fetch() method on your task request. It should be var tasks = Tasks.find().fetch();

TeeKz
  • 1
  • 1
  • Just like arrays, cursors got a `forEach` method, so that should not be a problem. The problem is that one can't achieve what Stijn wants in the way he has done. Actually, Meteor got no nice solution for working with relational collections at the moment. Read more about it here: https://www.discovermeteor.com/blog/reactive-joins-in-meteor/ – Peppe L-G May 28 '14 at 20:15