• Stars
    star
    200
  • Rank 195,325 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 11 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Meteor package to help you publish the count of a cursor, in real time

Publish Counts

A package to help you publish the count of a cursor, in real time.

Publish-counts is designed for counting a small number of documents around an order of 100. Due to the real-time capability, this package should not be used to count all documents in large datasets. Maybe some, but not all. Otherwise you will maximize your server's CPU usage as each client connects.

Table of Contents

Installation

$ meteor add tmeasday:publish-counts

API

Counts.publish [server]

Counts.publish(subscription, counter-name, cursor, options)

Simply call Counts.publish within a publication, passing in a name and a cursor:

Example 1

JavaScript
Meteor.publish('publication', function() {
  Counts.publish(this, 'name-of-counter', Posts.find());
});
Coffeescript
Meteor.publish 'publication', ->
  Counts.publish this, 'name-of-counter', Posts.find()
  return undefined    # otherwise coffeescript returns a Counts.publish
                      # handle when Meteor expects a Mongo.Cursor object.

The Counts.publish function returns the observer handle that's used to maintain the counter. You can call its stop method in order to stop the observer from running.

Warning: Make sure you call collection.find() separately for Counts.publish and the Meteor.publish return value, otherwise you'll get empty documents on the client.

For more info regarding the options parameter, see Options.

Counts.get [client]

Counts.get(counter-name)

Once you've subscribed to 'publication' (Ex 1), you can call Counts.get('name-of-counter') to get the value of the counter, reactively.

This function will always return an integer, 0 is returned if the counter is neither published nor subscribed to.

Counts.has [client]

Counts.has(counter-name)

Returns true if a counter is both published and subscribed to, otherwise returns false. This function is reactive.

Useful for validating the existence of counters.

Counts.noWarnings [server]

Counts.noWarnings()

This function disables all development warnings on the server from publish-counts.

Not recommended for use by development teams, as warnings are meant to inform library users of potential conflicts, inefficiencies, etc in their use of publish-counts as a sanity check. Suppressing all warnings precludes this sanity check for future changes. See the noWarnings option for fine-grained warning suppression.

Options

noReady

If you publish a count within a publication that also returns cursor(s), you probably want to pass {noReady: true} as a final argument to ensure that the "data" publication sets the ready state. For example, the following publication sends down 10 posts, but allows us to see how many there are in total:

Meteor.publish('posts-with-count', function() {
  Counts.publish(this, 'posts', Posts.find(), { noReady: true });
  return Posts.find({}, { limit: 10 });
});

nonReactive

If you specify {nonReactive: true} the cursor won't be observed and only the initial count will be sent on initially subscribing. This is useful in some cases where reactivity is not desired, and can improve performance.

countFromField

countFromField allows you to specify a field to calculate the sum of its numbers across all documents. For example if we were to store page visits as numbers on a field called visits:

{ content: 'testing', visits: 100 },
{ content: 'a comment', visits: 50 }

We could then publish them like:

Meteor.publish('posts-visits-count', function() {
  Counts.publish(this, 'posts-visits', Posts.find(), { countFromField: 'visits' });
});

And calling Counts.get('posts-visits') returns 150

If the counter field is deeply nested, e.g.:

{ content: 'testing', stats: { visits: 100 } },
{ content: 'a comment', stats: { visits: 50 } }

Then use an accessor function instead like:

Meteor.publish('posts-visits-count', function() {
  Counts.publish(this, 'posts-visits',
    Posts.find({}, { fields: { _id: 1, 'stats.visits': 1 }}),
    { countFromField: function (doc) { return doc.stats.visits; } }
  );
});

Note that when using an accessor function, you must limit the fields fetched if desired, otherwise Counts will fetch entire documents as it updates the count.

countFromFieldLength

countFromFieldLength allows you to specify a field to calculate the sum of its length across all documents. For example if we were to store the userIds in an array on a field called likes:

{ content: 'testing', likes: ['6PNw4GQKMA8CLprZf', 'HKv4S7xQ52h6KsXQ7'] },
{ content: 'a comment', likes: ['PSmYXrxpwg276aPf5'] }

We could then publish them like:

Meteor.publish('posts-likes-count', function() {
  Counts.publish(this, 'posts-likes', Posts.find(), { countFromFieldLength: 'likes' });
});

If the counter field is deeply nested, e.g.:

{ content: 'testing', popularity: { likes: ['6PNw4GQKMA8CLprZf', 'HKv4S7xQ52h6KsXQ7'] } },
{ content: 'a comment', popularity: { likes: ['PSmYXrxpwg276aPf5'] } }

Then use an accessor function instead like:

Meteor.publish('posts-likes-count', function() {
  Counts.publish(this, 'posts-likes',
    Posts.find({}, { fields: { _id: 1, 'popularity.likes': 1 }}),
    { countFromFieldLength: function (doc) { return doc.popularity.likes; } }
  );
});

Note that when using an accessor function, you must limit the fields fetched if desired, otherwise Counts will fetch entire documents as it updates the count.

noWarnings

Pass the option, noWarnings: true, to Counts.publish to disable its warnings in a development environment.

Each call to Counts.publish may print warnings to the console to inform developers of non-fatal conflicts with publish-counts. In some situations, a developer may intentionally invoke Counts.publish in a way that generates a warnings. Use this option to disable warnings for a particular invocation of Counts.publish.

This fine-grained method of warning suppression is recommended for development teams that rely on warnings with respect to future changes.

Template helpers

To easily show counter values within your templates, use the getPublishedCount or hasPublishedCount template helper.

Example:

<p>There are {{getPublishedCount 'posts'}} posts.</p>
<p>
  {{#if hasPublishedCount 'posts'}}
    There are {{getPublishedCount 'posts'}} posts.
  {{else}}
    The number of posts is loading...
  {{/if}}
</p>

Notes

Observer handle leak testing

The package includes a test that checks the number of observer handles opened and closed (to check for memory leaks). You need to run the enable-publication-tests-0.7.0.1 branch of percolatestudio/meteor to run it however.

Why doesn't this library count directly in Mongo? or...

Why does my MongoDB connection time-out with large (1000+) datasets?

This package is designed primarily for correctness, not performance. That's why it's aimed at counting smaller datasets and keeping the count instantly up to date.

To achieve perfect correctness in Meteor data layer, we use a database observer to know immediately if a relevant change has occurred. This approach does not necessarily scale to larger datasets, as the observer needs to cache the entire matching dataset (amongst other reasons).

Counting large datasets in this manner is suspected to cause database connections to time out (see #86).

An alternative approach would be to take a .count() of the relevant cursor (or perform an aggregation in more complex use cases), and poll it regularly to update the count. Bulletproof Meteor provides a proof of concept of this approach in their bullet-counter example.

We'd love to see someone publish a package for this use case! If you do end up making such a package, let us know and we'll link it here.

Scalable Count Packages

Compatibility with Meteor < 1.3

Publish-counts 0.8.0 introduces an explicit dependency on the underscore js library which may be incompatible with versions of Meteor below 1.3. Please upgrade Meteor to the latest version or, if you cannot, continue to use publish-counts 0.7.3.

Frequently Asked Questions

More information can be found in the FAQ Section of the issue tracker.

License

MIT. (c) Percolate Studio

publish-counts was developed as part of the Verso project.

More Repositories

1

meteor-synced-cron

A simple cron system for Meteor. It supports syncronizing jobs between multiple processes.
JavaScript
501
star
2

percolatestudio.com

JavaScript
249
star
3

meteor-migrations

Simple migration system for Meteor
JavaScript
245
star
4

ground-control

A next generation blog, built in Meteor.
CSS
183
star
5

meteor-momentum

Reactive animation package for Meteorjs
JavaScript
167
star
6

meteor-famous-demos

Demos from our devshop talk on Meteor+Famous
JavaScript
92
star
7

react-leaderboard

Meteor's leaderboard example app, rewritten in React.
JavaScript
74
star
8

atmosphere

Atmosphere - Meteor Packages
59
star
9

meteor-server-info

Query your Meteor app for diagnostics
JavaScript
59
star
10

meteor-google-api

A simple API encapsulating some common patterns regarding Google's APIs
JavaScript
48
star
11

meteor-segment.io

Basic Segment.io loader snippet Meteor package
JavaScript
29
star
12

famous-blog-examples

The code for the examples on our blog post http://blog.percolatestudio.com/engineering/the-future-of-javascript-animation-with-famous/
JavaScript
29
star
13

momentum-iron-router

JavaScript
27
star
14

league

CSS
26
star
15

development-guide

A set of (best?) practices that we follow at Percolate Studio.
Shell
23
star
16

mdg-localmarket

Recipes example app
17
star
17

cordova-plugin-safe-reload

Cordova plugin to watch and recover after a broken Meteor Hot Code Push.
JavaScript
14
star
18

amble

A proof of concept Apple Watch and Meteor application.
JavaScript
14
star
19

meteor-url-shortener

URL Shortener for a Meteor app.
JavaScript
13
star
20

meteor-wireframing

Wireframing tools for Meteor
JavaScript
13
star
21

safe-reload

Percolate Studio's Safe Reload Package for Meteor / Cordova
JavaScript
11
star
22

percolate-icons

Percolate Studio Icon Set Package
Less
8
star
23

meteor-detective

Snoop into your Meteor app
JavaScript
8
star
24

meteor-velocityjs

Meteor wrapper package for velocity.js
JavaScript
7
star
25

meteor-pack

Random odds and ends we use across our Meteor projects.
JavaScript
7
star
26

cordova-plugin-file-upload

Cordova plugin for non-multipart file uploads.
JavaScript
6
star
27

meteor-mixpanel

Light Mixpanel Loader package for Meteor.
JavaScript
5
star
28

mdg-todos

CSS
3
star
29

safe

Make method calls safely
JavaScript
3
star
30

collection-models

Simple model code for Meteor
JavaScript
3
star
31

meteor-factory-client

JavaScript
2
star
32

contact-form

JavaScript
2
star
33

tooltips

Tooltips for Meteor
JavaScript
2
star
34

collection-models-schemas

JavaScript
2
star
35

amble-victoria

Ruby
1
star
36

mdg-dashboard

JavaScript
1
star
37

cordova-plugin-file-transfer

Non Multipart version of the Cordova FileTransfer plugin
JavaScript
1
star
38

MeteorShower

JavaScript
1
star
39

mdg-leaderboard

Leaderboard example app redesign
1
star
40

mdg-recipes-landing

Landing page for recipes app
CSS
1
star
41

bound-form

A Meteor package for forms bound to their output via a reactive dictionary.
JavaScript
1
star
42

theme-percolate-blog

Percolate Studio blog WP theme
CSS
1
star