1

I have a very big data set, and I publish/subscribe only a part of it. (The last 100 objects) However, I must also go back and access other slice of this data set, but I cannot re-publish an other data set of the same name, and I do not want the "non live" selections to be synchronized across all clients.

What is the recommended way for doing it?

Thanks,

Andy G
  • 19,232
  • 5
  • 47
  • 69
Pivert
  • 755
  • 5
  • 17

4 Answers4

1

The name of your publish channel does not have to correspond to the collection name you're publishing. You can publish several sets from one collection:

Meteor.publish('currentArticles', function() {
  return Articles.find({}, {limit: 100});
});

Meteor.publish('allArticles', function(chunk) {
  return Articles.find({}, {limit: 100, skip: 100*chunk});
});
Hubert OG
  • 19,314
  • 7
  • 45
  • 73
  • Not sure, as when I will subscribe to allArticles, it will try to replicate the data set to the browser memory. And that's not an option because the data set is too big. – Pivert Sep 15 '13 at 09:11
  • You can use whatever filter you like in the publish methods, what I've written is just an example. I've tweaked it now to not send everything at once, it should be closer to what you actually need. – Hubert OG Sep 15 '13 at 11:29
0

Hubert's example would leave it up to the client to decide what to call down. If that is fine, I have nothing to add. If, however, you need to be a little more closed than that, you would need to establish either a new collection with a userId column to expose,

return SlicedArticles.find({_id: Meteor.userId()});

or an array on your existing article object to include the valid user ids.

Jim Mack
  • 1,437
  • 11
  • 16
0

Here is how I achieved the time slices display. Instead of replacing the table generated by the template & the subscribed data set, I created a new table. It's a bit more manual, but here it is.

On the server, I just expose a method called gethistory, that takes the upper and lower limit of the slice, fetch() the new data set and return the fetched data if the slice period is less than 30 minutes, otherwise returns false:

Meteor.methods({
    gethistory: function(utcfrom, utcto) {
        // If interval is lower than 30 minutes
        if ((utcto - utcfrom) < 1800 * 1000) {
                query = Mon.find({
                    "$and": [{
                        "utctime": {
                            "$gt": (new Date(utcfrom))
                            }   
                    }, {
                        "utctime": {
                            "$lt": (new Date(utcto))
                            }   
                    }]  
                    }, {
                    sort: {
                        utctime: 1
                    },  
                    limit: 500 
                })  
                res = query.fetch()
                return res 
        } else {
            return false
        }   
    }   
})

When I need a new slice of data to be displayed, I use the following code from the client (e.min & e.max contains the slice boundaries). In my code, this is called form the afterSetExtremes(e) section of a highchart displaying a full year, (check http://www.highcharts.com/stock/demo/lazy-loading if you're insterested in the highchart part)

Meteor.call('gethistory', e.min, e.max, function(error, data) {
    Session.set('histdata', data)
});

I have a template: Template.hist.historylines = function () { return Session.get('histdata') }

And an html part:

<body>
{{> hist}}
</body>

<template name="hist">
  <div>
   {{#if historylines}}
  <table>
    {{#each historylines}}
      {{> line}}
    {{/each}}
   {{else}}
     <p>You must select a period smaller than 30 minutes to get the details.</p>
   {{/if}}
  </table>
  </div>
</template>
<template name="line">
  <tr>
    <td>{{val1}}</td>
    <td>{{val2}}</td>
  </tr>
</template>
Pivert
  • 755
  • 5
  • 17
0

You can (and should) do this with publications instead of a Meteor.method, especially if you want live updates.

You may publish one collection on the server to different collections on the client, one which is 'live' and one which isn't (potentially saving some resources such as observers).

Server code:

Articles = new Meteor.Collection("articles");

// Static articles publication with no observer.
// More efficient than just doing  return Articles.find(); 
Meteor.publish("staticPub", function() {
    var sub = this;
    // Put your arguments in this find() for the "non-live" selection
    Articles.find().forEach(function(article) {
        sub.added("staticArticles", article._id, article);                  
    });

    sub.ready();    
});

// Live latest articles publication
Meteor.publish("latestPub", function() {
    // Only get things at most 30 minutes old
    var cutoff = +new Date - 30 * 60 * 1000;
    return Articles.find({ 
        utctime: {$geq: cutoff} 
    }, {
        limit: 500
    });
});

Client code:

StaticArticles = new Meteor.Collection("staticArticles");
Articles = new Meteor.Collection("articles");

Meteor.subscribe("staticPub");
Meteor.subscribe("latestPub");

It's also possible to push the latest articles to a collection with a different name on the client as well, although that would make the code here more verbose. For a review of what you can do with publications see https://stackoverflow.com/a/18880927/586086.

Community
  • 1
  • 1
Andrew Mao
  • 35,740
  • 23
  • 143
  • 224