Meteor publish virtual documents


#1

Hello there,
I implemented an event calendar with periodic events(like every week, every fourth day, last monday in month…)

Therefore I created a collection with the following fields:

events:{
title:String/sometitle
date:Date//the events date
period:String//sth like "2,w" for every two weeks or "3,m" for every 3. month
}

So now my approach is:

  1. publishing all events
  2. generate an Array which contains the constructed events for the next x days

The problem with this approach is, that i have an array now and no collection any more - which forces me to write my own filter and sort functions :confused:

Is there a way to somehow fill the clients collection with imaginary items? Then i could still use fitler functions on the collection…

I think this is a kind of awkward approach and if i’m doing this totally wrong a hint on how to do it better would be really nice :wink:

/**
 * generates an array with events based on the recurring logic in the database for the next 'duration' days
 * @param events database events .fetch() array
 * @param startdate the startdate to begin calculation
 * @type moment() date object
 * @param duration the duration in days (default 30)
 * @type time in days
 */
var applyRecurringLogic = function(events,startDate,duration){
    duration = typeof duration !== 'undefined' ? duration:30;
    /**
     * is intialized empty and then filled with all the database events and the additional generated events
     * @type {Array}
     */
    var bloatedArray = [];
    /**
     * contains the calculated endDate = currentDate + duration
     * @type Date
     */
    var endDate = moment(startDate).add(duration,'d');

    events.forEach(function(doc){
        if(doc.isRecurring === true){
            /**
             * [0]:1-x,[1]:w|m|d
             * @type {Array}
             */
            var split = doc.frequency.split(",");
            /**
             * contains the current Documents date
             * @type Date
             */
            var currentDocumentDate = moment(doc.startDate);
            //iterate till event leaves scope
            while(endDate >= currentDocumentDate){
                //check if event is already in scope
                if(currentDocumentDate > startDate){
                    doc.startDate = currentDocumentDate;
                    var newObj = JSON.parse(JSON.stringify(doc));
                    bloatedArray.push(newObj);
                }
                //iterate to next cycle
                currentDocumentDate = currentDocumentDate.add(split[0], split[1]);
            }
        }else{
            bloatedArray.push(doc);
        }
    });
    return bloatedArray;
};

The second problem with this approach is, that i get a lot of “duplicate id” errors.
Regards ,
Lukas


#2

One option can be to use temporary collection. Please check this link - http://stackoverflow.com/questions/28246879/how-to-make-a-temporary-collection-in-meteor


#3

Thanks this answer really helped me! :wink:
But I have a little follow up question on this:

This temporary collection is dependent on changes on the Events collection.
So every time the events collection changes, I have to reload the temporary collection - how can I hook to Database changes? I found this plugin: https://github.com/matb33/meteor-collection-hooks but it seems a bit overkill.

Is there a easier way to just observe the collection and rerun the function on any changes?


#4

Why not just publish documents which match data range ?


#5

@shock i don’t understand how this would help with my question? Because the documents(for recurring events) aren’t existent in the database - so there’s no way publishing them.


#6

well… that seems like collection in DB

anyway, you can use low level publish API to publish anything to any client side collection.


#7

@shock I hope my question was not that bad? :wink: not en english native - my problem isn’t publishing to the tempory collection. Everything works like a charm in this part of the application.

The Problem is that I need to somehow listen to changes in “Events” collection to rebuild my “TemporaryEvents” collection everytime an entry in Events is changed,inserted or removed.


#8

The usual way of doing this is to define your own _id for each document in your publication (don’t rely on the automatic _id). As long as this is a string and you can guarantee to be able to calculate it correctly for a document, it can be anything you like. Doing it like this means that reactive changes to your collection are done “for free” - you don’t have to run your own obervers.


#9

well, I still dont get why you cant use just standard publish with some nice selector to filter just events you need.
there are ways how to publish from Event collection to CustomEvent collection on client.

And you can even push anything from server to client side collection, so you can keep your mini-mongo nice queries.

But really you should better formulate what you want.

From Event collection publish documents which are “reoccuring” or match any specific query to client side collecttion XY.
Than we can talk how to do it meteor way.