• Stars
    star
    553
  • Rank 80,462 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 11 years ago
  • Updated 3 months ago

Reviews

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

Repository Details

Meteor.publishComposite provides a flexible way to publish a set of related documents from various collections using a reactive join

meteor-publish-composite

Project Status: Active – The project has reached a stable, usable state and is being actively developed. GitHub JavaScript Style Guide Language grade: JavaScript GitHub tag (latest SemVer) All Contributors

publishComposite(...) provides a flexible way to publish a set of related documents from various collections using a reactive join. This makes it easy to publish a whole tree of documents at once. The published collections are reactive and will update when additions/changes/deletions are made.

This project differs from many other parent/child relationship mappers in its flexibility. The relationship between a parent and its children can be based on almost anything. For example, let's say you have a site that displays news articles. On each article page, you would like to display a list at the end containing a couple of related articles. You could use publishComposite to publish the primary article, scan the body for keywords which are then used to search for other articles, and publish these related articles as children. Of course, the keyword extraction and searching are up to you to implement.

Found a problem with this package? See below for instructions on reporting.

Installation

$ meteor add reywood:publish-composite

Usage

This package exports a function on the server:

publishComposite(name, options)

Arguments

  • name -- string

    The name of the publication

  • options -- object literal or callback function

    An object literal specifying the configuration of the composite publication or a function that returns said object literal. If a function is used, it will receive the arguments passed to Meteor.subscribe('myPub', arg1, arg2, ...) (much like the func argument of Meteor.publish). Basically, if your publication will take no arguments, pass an object literal for this argument. If your publication will take arguments, use a function that returns an object literal.

    The object literal must have a find property, and can optionally have children and collectionName properties.

    • find -- function (required)

      A function that returns a MongoDB cursor (e.g., return Meteor.users.find({ active: true });)

    • children -- array (optional) or function

      • An array containing any number of object literals with this same structure
      • A function with top level documents as arguments. It helps dynamically build the array based on conditions ( like documents fields values)
    • collectionName -- string (optional)

      A string specifying an alternate collection name to publish documents to (see this blog post for more details)

    Example:

    {
        find() {
            // Must return a cursor containing top level documents
        },
        children: [
            {
                find(topLevelDocument) {
                    // Called for each top level document. Top level document is passed
                    // in as an argument.
                    // Must return a cursor of second tier documents.
                },
                children: [
                    {
                        collectionName: 'alt', // Docs from this find will be published to the 'alt' collection
                        find(secondTierDocument, topLevelDocument) {
                            // Called for each second tier document. These find functions
                            // will receive all parent documents starting with the nearest
                            // parent and working all the way up to the top level as
                            // arguments.
                            // Must return a cursor of third tier documents.
                        },
                        children: [
                           // Repeat as many levels deep as you like
                        ]
                    }
                ]
            },
            {
                find(topLevelDocument) {
                    // Also called for each top level document.
                    // Must return another cursor of second tier documents.
                }
                // The children property is optional at every level.
            }
        ]
    }

    Example with children as function:

    {
      find() {
          return Notifications.find();
      },
      children(parentNotification) {
        // children is a function that returns an array of objects.
        // It takes parent documents as arguments and dynamically builds children array.
        if (parentNotification.type === 'about_post') {
          return [{
            find(notification) {
              return Posts.find(parentNotification.objectId);
            }
          }];
        }
        return [
          {
            find(notification) {
              return Comments.find(parentNotification.objectId);
            }
          }
        ]
      }
    }

Examples

Example 1: A publication that takes no arguments.

First, we'll create our publication on the server.

// Server
import { publishComposite } from 'meteor/reywood:publish-composite';

publishComposite('topTenPosts', {
    find() {
        // Find top ten highest scoring posts
        return Posts.find({}, { sort: { score: -1 }, limit: 10 });
    },
    children: [
        {
            find(post) {
                // Find post author. Even though we only want to return
                // one record here, we use "find" instead of "findOne"
                // since this function should return a cursor.
                return Meteor.users.find(
                    { _id: post.authorId },
                    { fields: { profile: 1 } });
            }
        },
        {
            find(post) {
                // Find top two comments on post
                return Comments.find(
                    { postId: post._id },
                    { sort: { score: -1 }, limit: 2 });
            },
            children: [
                {
                    find(comment, post) {
                        // Find user that authored comment.
                        return Meteor.users.find(
                            { _id: comment.authorId },
                            { fields: { profile: 1 } });
                    }
                }
            ]
        }
    ]
});

Next, we subscribe to our publication on the client.

// Client
Meteor.subscribe('topTenPosts');

Now we can use the published data in one of our templates.

<template name="topTenPosts">
    <h1>Top Ten Posts</h1>
    <ul>
        {{#each posts}}
            <li>{{title}} -- {{postAuthor.profile.name}}</li>
        {{/each}}
    </ul>
</template>
Template.topTenPosts.helpers({
    posts() {
        return Posts.find({}, { sort: { score: -1 }, limit: 10 });
    },

    postAuthor() {
        // We use this helper inside the {{#each posts}} loop, so the context
        // will be a post object. Thus, we can use this.authorId.
        return Meteor.users.findOne(this.authorId);
    }
})

Example 2: A publication that does take arguments

Note a function is passed for the options argument to publishComposite.

// Server
import { publishComposite } from 'meteor/reywood:publish-composite';

publishComposite('postsByUser', function(userId, limit) {
    return {
        find() {
            // Find posts made by user. Note arguments for callback function
            // being used in query.
            return Posts.find({ authorId: userId }, { limit: limit });
        },
        children: [
            // This section will be similar to that of the previous example.
        ]
    }
});
// Client
var userId = 1, limit = 10;
Meteor.subscribe('postsByUser', userId, limit);

Known issues

Avoid publishing very large sets of documents

This package is great for publishing small sets of related documents. If you use it for large sets of documents with many child publications, you'll probably experience performance problems. Using this package to publish documents for a page with infinite scrolling is probably a bad idea. It's hard to offer exact numbers (i.e. don't publish more than X parent documents with Y child publications) so some experimentation may be necessary on your part to see what works for your application.

Arrow functions

You will not be able to access this.userId inside your find functions if you use arrow functions.

Reporting issues/bugs

If you are experiencing an issue with this package, please create a GitHub repo with the simplest possible Meteor app that demonstrates the problem. This will go a long way toward helping me to diagnose the problem.

More info

For more info on how to use publishComposite, check out these blog posts:

Note that these articles use the old pre-import notation, Meteor.publishComposite, which is still available for backward compatibility.

Contributors

Thanks goes to these wonderful people (emoji key):


Sean Dwyer

💻 📖 🤔 🚧

Seba Kerckhof

💻 🚧 👀 ⚠️

Richard Lai

🐛 💻

Simon Fridlund

💻

Patrick Lewis

💻

nabiltntn

💻

Krzysztof Czech

💻

Jan Dvorak

💻 📖 🚇 🚧 🔧

Koen [XII]

💻

This project follows the all-contributors specification. Contributions of any kind welcome!

More Repositories

1

meteor-autoform

AutoForm is a Meteor package that adds UI components and helpers to easily create basic forms with automatic insert and update events, and automatic reactive validation.
JavaScript
1,439
star
2

Meteor-CollectionFS

Reactive file manager for Meteor
JavaScript
1,051
star
3

meteor-collection2

A Meteor package that extends Mongo.Collection to provide support for specifying a schema and then validating against that schema when inserting and updating.
JavaScript
1,024
star
4

meteor-roles

Authorization package for Meteor, compatible with built-in accounts packages
JavaScript
920
star
5

meteor-simple-schema

Meteor integration package for simpl-schema
JavaScript
920
star
6

meteor-collection-hooks

Meteor Collection Hooks
JavaScript
657
star
7

ground-db

GroundDB is a thin layer providing Meteor offline database and methods
JavaScript
569
star
8

meteor-user-status

Track user connection state and inactivity in Meteor.
JavaScript
557
star
9

raix-push

DEPRECATED: Push notifications for cordova (ios, android) browser (Chrome, Safari, Firefox)
JavaScript
515
star
10

meteor-tabular

Reactive datatables for large or small datasets
JavaScript
363
star
11

meteor-autocomplete

Client/server autocompletion designed for Meteor's collections and reactivity.
CoffeeScript
350
star
12

meteor-scss

Node-sass wrapped to work with meteor.
JavaScript
311
star
13

meteor-partitioner

Transparently divide a single meteor app into several different instances shared between different groups of users.
CoffeeScript
152
star
14

meteor-timesync

NTP-style time synchronization between server and client, and facilities to use server time reactively in Meteor applications.
JavaScript
118
star
15

meteor-link-accounts

Meteor link account package. based on this PR https://github.com/meteor/meteor/pull/1133
JavaScript
116
star
16

mongo-collection-instances

🗂 Meteor package allowing Mongo Collection instance lookup by collection name
JavaScript
73
star
17

Meteor-EventEmitter

Client and server event emitter
JavaScript
72
star
18

meteor-postcss

PostCSS for Meteor
JavaScript
68
star
19

meteor-mocha

A Mocha test driver package for Meteor 1.3+. This package reports server AND client test results in the server console and can be used for running tests on a CI server or locally.
JavaScript
67
star
20

meteor-elastic-apm

Meteor Elastic APM integration
JavaScript
57
star
21

organization

Discussions on organization of the organization 🎩
41
star
22

meteor-schema-index

Control some MongoDB indexing with schema options
JavaScript
38
star
23

meteor-publication-collector

Test a Meteor publication by collecting its output.
JavaScript
33
star
24

meteor-collection-extensions

Safely and easily extend the (Meteor/Mongo).Collection constructor with custom functionality.
JavaScript
31
star
25

stratosphere

Meteor private package server
JavaScript
28
star
26

meteor-method-hooks

JavaScript
26
star
27

meteor-autoform-select2

Custom select2 input type for AutoForm
JavaScript
25
star
28

meteor-autoform-bs-datepicker

Custom "bootstrap-datepicker" input type for AutoForm
JavaScript
25
star
29

react-router-ssr

Simple isomorphic React SSR for Meteor with subscribed data re-hydration
JavaScript
24
star
30

denormalize

Simple denormalization for Meteor
JavaScript
20
star
31

meteor-autoform-bs-datetimepicker

Custom bootstrap-datetimepicker input type with timezone support for AutoForm
JavaScript
17
star
32

meteor-packages

Client for Meteor Package Server API
JavaScript
14
star
33

Packosphere

A Meteor package explorer for you, and if you are so inclined to help build it, by you.
TypeScript
13
star
34

meteor-schema-deny

Deny inserting or updating certain properties through schema options
JavaScript
12
star
35

check-npm-versions

Enforces "peer" npm dependencies in Meteor 1.3+ Atmosphere packages.
TypeScript
11
star
36

meteor-browser-tests

A helper package for Meteor test driver packages. Runs client tests in a headless browser.
JavaScript
11
star
37

template-package

Template package with CI and everything else to get started quickly with creating a new FOSS Meteor package.
JavaScript
10
star
38

meteor-stylus

A fork of meteor:stylus with mquandalle:stylus plugins
JavaScript
8
star
39

meteor-minifiers-autoprefix

JavaScript
6
star
40

meteor-autoform-bs-button-group-input

A Bootstrap button group theme for the "select-checkbox" and "select-radio" AutoForm input types
JavaScript
6
star
41

ground-minimax

Minimax is a thin layer for Meteor providing EJSON.minify and EJSON.maxify
JavaScript
6
star
42

meteor-typescript

Typescript compiler package
TypeScript
5
star
43

meteor-api-untethered

A collection of packages to make Meteor available to other environments.
JavaScript
5
star
44

awesome-meteor

Curated list of awesome Meteor.js things.
5
star
45

Meteor-EventState

DEPRECATED: Evented state
JavaScript
4
star
46

meteor-autoform-themes

Officially supported themes for aldeed:autoform
JavaScript
3
star
47

push

JavaScript
2
star