Code Monkey home page Code Monkey logo

meteor-publish-composite's Introduction

meteor-publish-composite

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.

Project

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

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);

Example 3: A publication from async function

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

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

publishComposite('postsByUser', async function(userId) {
    const user = await Users.findOneAsync(userId)
    const limit = user.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.
        ]
    }
});

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.

Testing

Run the following:

meteor test-packages reywood:publish-composite --driver-package meteortesting:mocha

The tests are executing a combination of methods and subscriptions. The quickest option was to add a pause after each operation (see usage of sleep() in ./tests/server.js), to allow for the publications to send down all the documents. However, this is flaky, so you may want to refresh the browser if you notice tests failing for no apparent reason.

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.

Alternatives

While we are happy that you find this package of value, there are limitations, especially on high traffic applications. There are also other solutions that can solve the problems that publish-composite solves, so here is a list of possible alternatives:

MongoDB Aggregations

MongoDB itself has a functionality called Aggregations which allows you to combine data from multiple collections into one document. It also has other useful features that you can utilize. The downside is that unless you use reactive-aggregate package the aggregations are not reactive and things it is not the easiest to learn or master.

GraphQL

GraphQL allows you to specify exactly which data you need and even embed child documents. Apollo GraphQL also has an official package and there is the apollo starter skeleton in Meteor itself to get you started quickly.

Contributors ✨

Thanks goes to these wonderful people (emoji key):

Sean Dwyer
Sean Dwyer

💻 📖 🤔
Seba Kerckhof
Seba Kerckhof

💻 👀 ⚠️
Richard Lai
Richard Lai

🐛 💻
Simon Fridlund
Simon Fridlund

💻
Patrick Lewis
Patrick Lewis

💻
nabiltntn
nabiltntn

💻
Krzysztof Czech
Krzysztof Czech

💻
Jan Dvorak
Jan Dvorak

💻 📖 🚇 🚧 🔧
Koen [XII]
Koen [XII]

💻

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

meteor-publish-composite's People

Contributors

aboire avatar alisnic avatar czeslaaw avatar davidyuk avatar dependabot[bot] avatar gabrielcazacu96 avatar jankapunkt avatar koenlav avatar manueltimita avatar nabiltntn avatar nandika-a avatar patrickml avatar rclai avatar redabourial avatar reywood avatar sebakerckhof avatar storytellercz avatar zimme avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

meteor-publish-composite's Issues

publishComposite on meteor.com ?

Hi Sean,
This is my first post on github, so please be indulgent ;-). I am developing an online strategy game where each player has a personal field of view that can evolve during the game when he conquers more territories (in fact when he drops some cubes on the map, yes that's kind of an abstract game..). Therefore the server publishes only the tiles owned by the player + somes tiles around them. Players can stack cubes on a tile or erase an opponent cube by dropping one on the concerned tile. If they drop a cube on a tile where there's just one opponent cube, they become the owner of the cube. I struggled to achieve this reactive publication but I've found your package and it was actually quiet simple : it works perfectly on my local server and on my nitrous.io cloud IDE so thanks a lot for this package ! Nevertheless, when I deploy on meteor.com, there is a case that doesn't work : when a player drops a cube on a tile where there's just one opponent cube, the DB is modified but there is no "reaction" on the client side. I assure you it works on my local server. I am kind of confused here so I'm looking for your help ! I put my publish & update code below, do not hesitate to ask me for more details if needed !

Meteor.publishComposite('map', {
  find: function() {
    var currentUserId = this.userId;
    if(currentUserId) {
      var username = Meteor.users.findOne({_id: currentUserId}).username;
      return Map.find({player: username});
    }
  },
  children: [
    {
      find: function(playerTile) {
        var queryArray = [];
        var x_max = Math.floor(visibility(playerTile.z));
        for(var x=0; x <= x_max; x++) {
          var y_max = x_max-x;
          for(var y=0; y<=y_max; y++) {
            queryArray.push({$and: [{x: playerTile.x+x}, {y: playerTile.y+y}]});
            queryArray.push({$and: [{x: playerTile.x-x}, {y: playerTile.y+y}]});
            queryArray.push({$and: [{x: playerTile.x+x}, {y: playerTile.y-y}]});
            queryArray.push({$and: [{x: playerTile.x-x}, {y: playerTile.y-y}]});
          }
        }
        return Map.find({$or: queryArray});
      }
    }
  ]
});

Meteor.methods({
  'dropCube': function(tile) {
    var currentUserId = Meteor.userId();
    var username = Meteor.users.findOne({_id: currentUserId}).username;
    var existingTile = Map.findOne({x:tile.x, y:tile.y});
    if (existingTile) {
      if(existingTile.player != username) {
        if(existingTile.z > 1) {
          Map.update(existingTile._id, {$set: {z: existingTile.z-1}});
        } else {
          Map.update(existingTile._id, {$set: {player: username}});
        }
      } else {
        Map.update(existingTile._id, {$set: {z: existingTile.z+1}});
      }
    }
    else {
      Map.insert({x: tile.x, y:tile.y, z:1, player: username});
    }
  }
});

trouble publishing on 0.9.4

Hi,
Despite the examples in the readme, I'm having trouble getting this package to work. I'm running Meteor 0.9.4. My setup is very simple:

The publication

Meteor.publishComposite 'works', {
  find: ->
    Works.find {}, {
      sort: {createdAt: -1}
    }
  children: [
    {
      find: (work) ->
        Meteor.users.find {
          _id: work.artistId
          limit: 1
        }
    }
  ]
}

And my route subscribes like this

Router.map ->
  @route 'workList', {
    waitOn: ->
      return @subscribe('works')
  }

When I call Meteor.users.find() on the client, the collection only contains my current logged-in user, not any of the users that should be loaded via publishComposite. Any ideas?

Or Is there a complete sample app available somewhere? Having a bit more context would help a lot. Preferably using Coffeescript and Iron-Router, but without would be great as well.

Cheers!

Publish with conditions

How do i publish only if a user is logged in with this package?

Meteor.publish 'usersData', ->
  if @userId
    Meteor.users.find {},
      fields:
        emails: 1
        profile: 1
  else
    @ready()

Fetches leading up to return query in find are not running reactively.

I've been using mrt:reactive-publish successfully but I wanted to give publish-composite a try since it's kept up to date and the doc says it's reactive. I'm having trouble getting the following publication to update reactively. It doesn't use any children queries, but it needs to call a couple of fetches to pass into the final return query :

Meteor.publishComposite('biddersByProduct', function(productId) {
    return {
        find: function() {
            console.log("biddersByProduct is running...");
            var physicalBids = PhysicalBids.find({productId: productId}).fetch();
            var onlineBids = OnlineBids.find({productId: productId}).fetch();
            var combinedBidIds = _.union(_.pluck(physicalBids, "bidderId"), _.pluck(onlineBids, "bidderId");
            return Bidders.find({_id: {$in: combinedBidIds}});
        }
    }
 });

Basically a Bidder can create several different PhysicalBids and OnlineBids on a Product. So one of my templates is a product page that needs to show all the Bidders across all PhysicalBids and OnlineBids... reactively.

Is something like this meant to be supported reactively? I don't need any other child collections - just the top level one. But the way my database is set up - it needs to fetch like this. So far I have not been able to get it to work. The console.log call only fires upon template loading and never again. The idea is that it fires every time a new Bidder creates a PhysicalBid or OnlineBid on a particular Product. It works using mrt:reactive-publish.

NOTE: In mrt:reactive-publish I have to add {reactive: true} to the fetch calls and the final return query, but I think that was just a flag for reactive-publish.

Exception when republishing null cursor

Exception in queued task: TypeError: Cannot call method 'rewind' of undefined
    at Publication.republish (packages/publish-composite/publish_composite.js:135)
    at packages/publish-composite/publish_composite.js:182
    at Array.forEach (native)
    at Function._.each._.forEach (packages/underscore/underscore.js:105)
    at Publication._republishChildrenOf (packages/publish-composite/publish_composite.js:180)
    at Object.observeHandle.cursor.observe.changed (packages/publish-composite/publish_composite.js:112)
    at observeChangesCallbacks.changed (packages/minimongo/observe.js:162)
    at self.applyChange.changed (packages/minimongo/observe.js:66)
    at packages/mongo-livedata/observe_multiplex.js:163

publication limit the total amount of children

So I have a schema where posts can be "starred" by users, and users can "follow" other users. A user's feed consists of all the posts that are starred by the users they follow.

Now the question is how to I build a publication:

Meteor.publishComposite 'feed', (limit) ->
  # user must be logged in
  unless @userId
    return
  return {
    find: ->
      # a follow contains {userId, followId}, where userId is following followId
      # here we're getting all the follow objects belonging to the user
      Follows.find({userId:@userId})
    children: [
      { 
        find: (follow) ->
          # get the stars for all the people the user is following
          # a star consists of {userId, eventId}
          Stars.find({userId: follow.followId})
        children: [
          {
            find: (star) ->
              # get all the posts corresponding to the star
              Posts.find({_id:star.eventId}, {sort:{name:1, date:-1}, limit:limit})
          }
        ]
      }
    ]
  }

The problem here is that I want to sort and limit all of the posts. I believe this implementation doesnt actually sort or limit anything because we're just finding a single post here by _id...

Any ideas here?

fast-render and publish composite

Hello,

is this package compatible with fast-render? I would like to know if I need to take care about special adjustment in the code.

Thanks for this great package by the way!

Transform a document before publishing

As you know, there are two methods to implement a publish function:

  1. By returning a cursor (or an array of cursors)
  2. By using this.added() / this.changed() / this.removed(), usually from cursor.observeChanges() callbacks

Let's consider these three use cases for method 2:
a. You want to add a field to a document before publication
b. You want to remove a field from a document before publication
c. You want to do both, for example to combine several secret fields into one public field

Does meteor-publish-composite allow for these three use cases?

Resolved, no issue

Resolved my issue, I had a mistaken extra users.search that I was apparently leaking out to unexpected places.

Changelog

A changelog would be nice.

Thanks for the package.

Removal of top level documents does not cause removal of children

Gist with an example. Create Meteor app, replace its sources with my example and navigate to the main page. Check some of the items - corresponding 'authors' will appear in the bottom. But if you uncheck some items, authors won't disappear (even if there were no 'diamon' joins).

Refreshing the page fixes the subscription.

Object has no method _getCollectionName

I am receiving the above error and the following output:

TypeError: Object  has no method '_getCollectionName'
W20150728-18:13:33.322(-5)? (STDERR)   at Publication._getCollectionName   (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:130:63)
W20150728-18:13:33.322(-5)? (STDERR)   at Publication.unpublish (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:108:44)
W20150728-18:13:33.322(-5)? (STDERR)   at /Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:186:21
W20150728-18:13:33.323(-5)? (STDERR)   at [object Object].eachChildPub (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:282:9)
W20150728-18:13:33.323(-5)? (STDERR)   at [object Object].eachChildPub (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:240:13)
W20150728-18:13:33.323(-5)? (STDERR)   at Publication._unpublishChildrenOf (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:185:24)
W20150728-18:13:33.323(-5)? (STDERR)   at Publication._removeDoc (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:178:10)
W20150728-18:13:33.323(-5)? (STDERR)   at Publication.<anonymous> (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:150:14)
W20150728-18:13:33.324(-5)? (STDERR)   at Publication.execCallbackOnDoc (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:232:18)
W20150728-18:13:33.324(-5)? (STDERR)   at Function._.each._.forEach (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/underscore.js:147:22)
W20150728-18:13:33.324(-5)? (STDERR)   at [object Object].eachDocument (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:231:7)
W20150728-18:13:33.324(-5)? (STDERR)   at Publication._unpublishAllDocuments (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:149:24)
W20150728-18:13:33.324(-5)? (STDERR)   at Publication.unpublish (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:110:10)
W20150728-18:13:33.324(-5)? (STDERR)   at /Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:427:17
W20150728-18:13:33.324(-5)? (STDERR)   at /Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/ddp.js:1882:7
W20150728-18:13:33.324(-5)? (STDERR)   at Array.forEach (native)
W20150728-18:13:33.324(-5)? (STDERR)   at Function._.each._.forEach (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/underscore.js:139:11)
W20150728-18:13:33.325(-5)? (STDERR)   at [object Object]._.extend._callStopCallbacks (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/ddp.js:1881:7)
W20150728-18:13:33.325(-5)? (STDERR)   at [object Object]._.extend._deactivate (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/ddp.js:1871:10)
W20150728-18:13:33.325(-5)? (STDERR)   at [object Object].subscriptionProto._deactivate (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/meteorhacks_kadira.js:2646:24)
W20150728-18:13:33.325(-5)? (STDERR)   at [object Object]._.extend._stopSubscription (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/ddp.js:1609:30)
W20150728-18:13:33.325(-5)? (STDERR)   at [object Object]._.extend.protocol_handlers.unsub (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/ddp.js:1417:12)
W20150728-18:13:33.325(-5)? (STDERR)   at [object Object].sessionProto.protocol_handlers.unsub (/Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/meteorhacks_kadira.js:2464:40)
W20150728-18:13:33.325(-5)? (STDERR)   at /Users/rfines/Projects/eventr.io/.meteor/local/build/programs/server/packages/ddp.js:1374:43

from a publication that looks like:

Meteor.publishComposite('estimates', function() {
return {
    find: function() {


        var c = Companies.findOne({$or:[{
            createdBy:this.userId
        },{
            authorizedUsers:{$in:[this.userId]}
        }]});
        if(c){
            return Estimates.find({$or:[{vendorApprover:c._id},{exhibitorApprover:c._id}]});
        }
    },
    children: [
        {
            find: function(estimate) {
                return Files.find({_id: {$in: estimate.files || []}});
            }
        },

        {
            find: function(estimate) {
                return CartItems.find({_id:estimate.cartItemId});
            },
            children:[
                {
                    find:function(ci, estimate){
                        return Booths.find({_id: ci.boothId});
                    }   
                },
                {
                    find:function(ci, estimate){
                        return Products.find({_id: ci.product._id});
                    }
                },
                {
                    find:function(ci, estimate){
                        return Shows.find({_id:ci.showId});
                    }
                },
                {
                    find: function(ci,estimate) {
                        return Carts.find({_id: ci.cartId});
                    },

                },
            ]

        },
        {
            find:function(estimate){
                return Companies.find({_id:{$in:[estimate.vendorApprover, estimate.exhibitorApprover]}});
            }
        },
    ]
}
});

It is dramatically affecting the loading times of the page it is on, though the documents do eventually get published to the client, it takes a minute or so for them to appear. Can you give me any guidance on what I might be doing wrong?

Suddenly things stopped working :)

Hi, could be that this issue has multiple possible causes (Meteor 1.1, collection-hooks and having tried out velocity testing), but today I suddenly starting getting all kinds of errors like this:

I20150331-10:00:07.211(2)? Exception in queued task: TypeError: Object #<Document> has no method '_getCollectionName'
I20150331-10:00:07.212(2)?     at Publication._getCollectionName (packages/reywood:publish-composite/lib/publication.js:74:1)

Any ideas?

compatibility with meteorhacks:unblock

Hello,
I would like to know if there is any plan of supporting meteorhacks:unblockinside of this package. The unblock package helped a lot to improve the page speed on my app. Did you have any experience with it? Thanks

Error: Doc not found in list: reywood_publish-composite.js line 210

This error only appears in my Cucumber log, seems not to affect my app in any way and does not reference any code in my app. Meteor-publish-composite seems to be a dependency of some other package; I did not add it explicitly myself. Perhaps it is a accident waiting to happen :

Exception in queued task: Error: Doc not found in list: 7bJXeKfHTwos7Ekc8
  at [object Object].addChildPub (/tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:210:15)
  at Publication.createChildPublication (/tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:136:28)
  at Array.forEach (native)
  at Function._.each._.forEach (/tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/underscore.js:139:11)
  at Publication._publishChildrenOf (/tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:134:7)
  at Object.added (/tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:86:22)
  at [object Object].observeChangesCallbacks.added (/tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/minimongo.js:3901:28)
  at self.applyChange.added (/tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/minimongo.js:3801:44)
  at /tmp/meteor-test-run49uzxg/.meteor/local/build/programs/server/packages/mongo.js:1852:30
  at Array.forEach (native)

I'd like to know if I am the only one seeing this. If you need further details, I'll be happy to oblige.

I'm running it in a Xubuntu 14.04 client guest of a KVM virtual machine.
It appears exactly four times, one immediately after the other, and only during startup of my Cucumber/Velocity testing.

Publish composite with Router

'client' collection:
{
"name" : "Test",
"code" : "test",
"createdAt" : ISODate("2015-01-01T20:29:05.290Z"),
"classifications" : [
{
"id" : "DS8QAaFnk5XHbcFhH"
},
{
"id" : "tFKDJi7s3PFJbHpCu"
},
{
"id" : "Htdv9RKrrCbYwPpEt"
}
]
"_id" : "rzaC7fdmrE6KTgWXF"
}

'classification' collection:
{
"classification" : "Quick & Dirty Format",
"isActive" : true,
"_id" : "DS8QAaFnk5XHbcFhH"
}
{
"classification" : "Web search",
"isActive" : true,
"_id" : "Htdv9RKrrCbYwPpEt"
}
{
"classification" : "Reformatting",
"isActive" : true,
"_id" : "tFKDJi7s3PFJbHpCu"
}

Router:

Router.route('client/:_id', {
path : 'client/:_id',
template : 'viewClient',
name : 'view.client',
layoutTemplate : adminLayout,
yieldTemplates : {
footer: {to: footer}
},
data : function() {
return Client.findOne(this.params._id);
}
});

Template.viewClient.helpers({
classifications : function() {
return WorkClassification.findOne(this.client.classifications.id);
}
});

Publish composite:

Meteor.publishComposite('client', {
find: function() {
return Client.find();
},
children: [
{
find: function(client) {
return WorkClassification.find({ _id : client.classifications.id});
}
}
]
});

I could get client info from routes. But exceptions raised on helpers function with return statement for classifications.

I want to display classification from classification collection using classification id from client collection. Already i have done publish composite for other projects.

Can we add more data context for composite?

Turning off reactivity for specific publications

First off, I really like this package and use it liberally. My only problem with it right now is that I am running into a case where I need to subscribe to a composite publication but I don't want it to update when I update documents.
Here is a breakdown of my use case:

I have a platform that is built as a collection of microservices, one of the services controls all access to the data through publications. The other services, which are all meteor apps, then subscribe to this data using a DDP connection and they loop over the published data to do some processing on the documents on a scheduled basis. Because the publications are reactive, the methods that do the processing never stop running because the publication continually updates the subscription when I update one of the top level documents.

I was wondering if there is a way to add an option to turn reactivity off for specific subscriptions or publications? Or maybe this is already possible?

Thanks

Trigger error callbacks on errors within nested functions

It is possible to pass an onError callback to Meteor.subscribe that is fired when there is an error within the publication or the publication explicitly calls this.error().

This doesn't appear to work if the error occurs within a nested find function (although explicitly calling this.error() does still work) -- that is ...

Meteor.publishComposite('mySub', {
  find: function() {
    return Universes.find();
    throw new Meteor.Error(500, "error"); // Triggers onError callback
  },
  children: [
    { 
      find: function(doc) {
        throw new Meteor.Error(500, "error"); // Does not trigger onError callback
      }
    }, {
      find: function(doc) { 
        this.error(500); // Triggers onError callback
      }
    }
  ]
});

It'd be nice if publish-composite had an option to automatically wrap each child find function in a try/catch block and call this.error if any of them fail.

Upsert support

It seems that the hooks are not called when upsert is used.

I had the bug that the publication doesn't publish any data because softRemovable() was used and the documents were inserted via upsert. This way no documents are published because the softRemovable()-Functionality prevents publishing of documents which doesn't use the softRemovable()-Functionality.

publish composite returns the docs in two collections client side

I am using publish composite and it is returning the docs into their own respective collections on the client as opposed to just one collection. Here is my code:

Meteor.publishComposite('userAchievements', {
    find: function() {
        if (!this.userId) {
            return;
        }
        var user = Meteor.users.findOne({ _id: this.userId });
        //Meteor._debug(user);
        if (!user.profile.xuid) {
            Meteor._debug("no xuid");
            return;
        }
        return collectionOne.find({ userId: this.userId });
    },
    children: [
        {
            find: function(collectionOne) {
                return collectionOne.find({ _id: collectionOne.collectionTwoId });
            }
        }
    ]
});

How would I get it to just return one cursor?

Borked in meteor 0.9.2.1

W20140917-00:14:12.094(-7)? (STDERR) TypeError: Object #<Object> has no method 'publishComposite'

etc.

Only publishing first parent version 1.3.0

Hi,
I upgraded to 9.2.1 and cant seem to publish children. Here is an example:

Meteor.publishComposite('client-detail',function(id){

return{

    find:function(){

        return Clients.find({clientId:id});
    },
    children:[

        {
            find:function(client){
                return Evaluations.find({clientId:client._id});
            }

        }



    ]




}

});

Thanks Chris

strange error..

I20150327-16:37:13.264(1)? Exception in queued task: TypeError: Object # has no method 'getCollectionName'
I20150327-16:37:13.264(1)? at Publication.getCollectionName (packages/reywood:publish-composite/lib/publication.js:74:1)
I20150327-16:37:13.264(1)? at Publication.publish (packages/reywood:publish-composite/lib/publication.js:15:1)
I20150327-16:37:13.264(1)? at Publication.createChildPublication (packages/reywood:publish-composite/lib/publication.js:81:1)
I20150327-16:37:13.264(1)? at Array.forEach (native)
I20150327-16:37:13.264(1)? at Function.
.each.
.forEach (packages/underscore/underscore.js:105:1)
I20150327-16:37:13.264(1)? at Publication._publishChildrenOf (packages/reywood:publish-composite/lib/publication.js:78:1)
I20150327-16:37:13.264(1)? at Object.added (packages/reywood:publish-composite/lib/publication.js:30:1)
I20150327-16:37:13.265(1)? at [object Object].observeChangesCallbacks.added (packages/minimongo/observe.js:153:1)
I20150327-16:37:13.265(1)? at self.applyChange.added (packages/minimongo/observe.js:53:1)
I20150327-16:37:13.265(1)? at packages/mongo/observe_multiplex.js:183:1

soop integrates publish-composite

Hi, I would like to tell you about my new package soop, Simple Object Oriented Programming, where I integrate publish-composite.
I tell you if you had an opinion about the integration of your packages.
I'm still not sure if that kind of programming is useful with Meteor, but I want to give it a try. Thanks for your attention.

Feature request: restrict which cursors are published

At the moment, everything returned by a top-level "find" is automatically published to the client, but I only want the children to be published.

Similarly, sometimes you only want certain fields to be published, but you need all the fields to run the child query. For example, I have a field user.secret which I use as part of a child query, but I don't want to publish that field to the client.

The first feature can be implemented by an option "internal: true" or similar, the second by adding a field specifier to the options, eg. "fields: { secret: false }"

Publications are leaking(!) to other routes for current user

I have two publications:

Meteor.publishComposite('allPostsWithComments', {
  find: function(){
    return Posts.find({"status.deleted": false}, POST_OPTIONS);
  },
  children: [
    {
      // find related post owner
      find: function(post, activity){
        return Meteor.users.find({_id: post.user_id }, USER_OPTIONS );
      },
    },
    {
      // find related post comments
      find: function(post, activity){
        return Comments.find( { post_id: post._id, "status.deleted": false } );
      }
    },
  ]
});
Meteor.publishComposite('onePost', function(postId) {
  return {
    find: function() {
      // Find posts made by user. Note arguments for callback function
      // being used in query.
      return Posts.find({ _id: postId }, POST_OPTIONS);
    },
    children: [
      {
        find: function(post){
          // publish post owner
          return Meteor.users.find({_id: post.user_id}, USER_OPTIONS);
        },
      },
      {
        find: function(post){
          // publish post comments
          return Comments.find({post_id: post._id, "status.deleted": false});
        },
        children: [
          {
            find: function(comment, post){
              // publish users related to comments
              return Meteor.users.find({_id: comment.user_id}, USER_OPTIONS);
            }
          }
        ]
      }
    ]
  }
});

And two routes:

this.route('explore', {
  waitOn: function () {
    // return one handle, a function, or an array
    return [
      subsManager.subscribe('allPostsWithComments'),
    ];
  },
});
this.route('postShow', {
  path: '/post/:_id',
  waitOn: function () {
    return [
      subsManager.subscribe('onePost', this.params._id),
    ];
  },
  data: function () {
    return { post: Posts.findOne({_id: this.params._id}) };
  },
  yieldRegions: {
    '_postOptions': {to: 'options'},
    '_headerBack': {to: 'header'},
    '_newCommentFooter': {to: 'footer'},
  },
});

As you can see in this scenario in "onePost" publication I'm not filtering posts by "status.deleted: false". That's because I want to publish deleted post only to "postShow" route and if it's deleted, I'm showing manual message to user: "This post has been deleted".
But I do filter by "status.deleted: false" on "explore" page as you can see in "allPostsWithComments" publish.

Now here's the problem: when I delete the post in "postShow" page, it's showing correctly deleted message and redirects me back to "explore" page and the currently deleted post is shown there and in all other routes as well for my current user until I hit refresh in my browser!. It's working normally for other users and the post disappears from their "explore" page when it's getting deleted. It's also working normally for my current user only after I hit refresh page.

PS: I tried navigating with Iron Router through both Router.go() and <a href="/explore"></a> and result is the same.

Publication error

I check to see if a user is logged in to publish:

Meteor.publishComposite 'records', () ->
  if @userId
    return {
      find: ->
        r = Records.find {ownerId: @userId}
        if r then return r else return false
      children: [{
        find: (record) ->
          if record?.receiptId?
            Receipts.find record.receiptId
        }]}
  else
    return {}

And sometime, like when I logout, I get a weird error like this:

I20150121-17:46:30.854(-8)? Exception from sub nm4iMHFpRBzNsgsp4 TypeError: Cannot call method 'apply' of undefined
I20150121-17:46:30.856(-8)?     at [object Object].Publication._getCursor (packages/reywood:publish-composite/lib/publication.js:76:1)
I20150121-17:46:30.856(-8)?     at [object Object].Publication.publish (packages/reywood:publish-composite/lib/publication.js:11:1)
I20150121-17:46:30.856(-8)?     at [object Object].<anonymous> (packages/reywood:publish-composite/lib/publish_composite.js:12:1)
I20150121-17:46:30.856(-8)?     at packages/matb33:collection-hooks/collection-hooks.js:218:1
I20150121-17:46:30.856(-8)?     at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20150121-17:46:30.857(-8)?     at [object Object]._handler (packages/matb33:collection-hooks/collection-hooks.js:217:1)
I20150121-17:46:30.857(-8)?     at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1599:1)
I20150121-17:46:30.857(-8)?     at [object Object]._.extend._runHandler (packages/ddp/livedata_server.js:943:1)
I20150121-17:46:30.857(-8)?     at packages/ddp/livedata_server.js:737:1
I20150121-17:46:30.857(-8)?     at Function._.each._.forEach (packages/underscore/underscore.js:113:1)

When record changes, only add/remove children that are different

Currently, when a record changes, all of its children are unpublished and then re-published. This ensures that the composite tree is up to date, but most likely results in a lot of unnecessary traffic. A proper diff should be done between the old children and the new, and only the changes should be sent up to the client.

Publishing large documents causes Exception from task: [RangeError: Maximum call stack size exceeded]

Returning a large document in a find that has children defined seems to cause the following error: Exception from task: [RangeError: Maximum call stack size exceeded]

A workaround that works fine in my case is to limit the publication in the find to only the fields that are needed for the child subscription, but it won't work for you if you need the whole document.

In my example, documents in the exam collections have a field that contains a rather large object.

Doing this works fine:

Meteor.publishComposite( 'examSolutions', function( examId ){
  return {
    'find': function() {
        return Exams.find( { _id: examId}, { fields: { defaultGradingSchemeId: true } } );
      }
    },
    children: [
      {
        find: function( exam ){
          return Solutions.find( { examGradingSchemeId: exam.defaultGradingSchemeId } );
        }
      }
    ]
  };
});

But doing the following will cause the range error:

Meteor.publishComposite( 'examSolutions', function( examId ){
  return {
    'find': function() {
        return Exams.find( { _id: examId} );
      }
    },
    children: [
      {
        find: function( exam ){
          return Solutions.find( { examGradingSchemeId: exam.defaultGradingSchemeId } );
        }
      }
    ]
  };
});

Here is the full stack trace:

Exception from sub examSolutions id rkCwGzF6S3n8PxkEt [object Object]
at Object.Future.wait (/home/user7/.meteor/packages/meteor-tool/.1.1.3.iasc1e++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:398:15)
at [object Object]._.extend.runTask (packages/meteor/fiber_helpers.js:81:1)
at [object Object]._.extend.addHandleAndSendInitialAdds (packages/mongo/observe_multiplex.js:47:1)
at [object Object].MongoConnection._observeChanges (packages/mongo/mongo_driver.js:1179:1)
at [object Object].Cursor.observeChanges (packages/mongo/mongo_driver.js:854:1)
at Function.LocalCollection._observeFromObserveChanges (packages/minimongo/observe.js:177:1)
at [object Object].Cursor.observe (packages/mongo/mongo_driver.js:848:1)
at Publication.publish (packages/reywood:publish-composite/lib/publication.js:18:1)
at [object Object]._handler (packages/reywood:publish-composite/lib/publish_composite.js:12:1)
at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1617:1)

Obviously for large documents passing the entire document as an argument to the added, changed or removed function of observe is not going to work, but maybe we can explicitly specify which fields the child subscriptions need to know and pass an object that's been reduced to only the _id and those fields.

Modifying the relation field causes a race condition

Hello,

We encounter an issue in wekan/wekan#61 related to the update of data published by publishComposite in a environment with latency between the client and the server (it works in local, but we have the bug in production).

I'm not sure what the problem exactly is, it seems to be related to the modification of the field that is used to make the relation in the publishComposite function. To make this bug easier to fix I manage to create a minimal reproduction:

https://github.com/mquandalle/meteor-publish-composite-latency-bug

You can clone the above repository and launch meteor. The UI will say "Max works on Work harder" and a few seconds later "Max works on Play harder". However if you deploy this application (for instance on the meteor cloud) it will not work anymore. I commented the code, but if what's going on is not clear, feel free to ask me here.

Performance

Can you please document some benchmarks addressing performance and what to / what NOT to do advices?

Please Give example how to loop the post collection

Meteor.publishComposite('posts', function(doc) {
    return {
        find: function() {
            console.log('displaying some posts');
            return Posts.find(doc);
        },
        children: [
            {
                 find: function(post) {
                    console.log('displaying some user in relation with post');
                    return Meteor.users.find({_id: post.createdUserId});
                }
            }
        ]
    }
});

//this is just example
Meteor.subscribe('posts', {});

//this is post which will be passed to view from iron router controller
return {
posts: Post.find(),
}
//how to retrieve user name in post?
{{#each posts}}
    {{_id}} <!-- called the posts id -->
    {{title}} <!-- called the posts title -->
    {{user.profile.name}} <!-- here is the question, how to get the user.profile.name? -->
{{/each}}

Thanks

Support returning objects from find

Currently find requires returning a cursor, but I've run into a use case where I'd like to return a static object, such as a placeholder image.

Meteor.publishComposite('articles', function publishFunction(user) {
  return {
    find: function () {
      return Articles.find(...);
    },
    children: [
      {
        find: function (article) {
          return (article.source) ?
            NewsSources.find({
              name: article.source.name
            }, {
              limit: 1,
              fields: { favicon: 1 }
            })
          : {
              favicon: '/some/default/favicon.png'
            };
        }
      }
    ]
  };
});

When trying that, I get an error TypeError: Object #<Object> has no method '_getCollectionName'. It would be nice to have support for returning objects, of course without children allowed in that case.

Reactive publish

Is it possible to user the reactive publish package with publish composite?

https://github.com/Diggsey/meteor-reactive-publish

It would be great to be able to do it, I've some complex publication that depends on other collection cursor only in some cases so I can't do it using publish composite only.

Any ideas?

Clarification request: does it support chaning foreign keys?

Say, if I change post's author, will another author be automatically re-published instead of the old one? I've looked into the code and I think that that's not the usecase, but I'm not sure. Anyway, this issue can be used as a feature request instead.

Error when logging out

for some reason I am receiving this error when logging out:

I20150707-10:23:10.082(-4)? Exception from sub projects id Hr8aJgXRcEsFnDSDQ TypeError: Cannot read property 'children' of undefined
I20150707-10:23:10.082(-4)?     at new Publication (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:61:35)
I20150707-10:23:10.082(-4)?     at [object Object].<anonymous> (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/reywood_publish-composite.js:423:19)
I20150707-10:23:10.083(-4)?     at /Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/matb33_collection-hooks.js:242:21
I20150707-10:23:10.083(-4)?     at [object Object]._.extend.withValue (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/meteor.js:989:17)
I20150707-10:23:10.083(-4)?     at [object Object]._handler (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/matb33_collection-hooks.js:241:28)
I20150707-10:23:10.083(-4)?     at maybeAuditArgumentChecks (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/ddp.js:2445:12)
I20150707-10:23:10.083(-4)?     at [object Object]._.extend._runHandler (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/ddp.js:1778:17)
I20150707-10:23:10.083(-4)?     at [object Object].MeteorX.Subscription._runHandler (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/meteorhacks_unblock.js:61:22)
I20150707-10:23:10.084(-4)?     at [object Object].MeteorX.Session._startSubscription (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/meteorhacks_unblock.js:49:7)
I20150707-10:23:10.084(-4)?     at [object Object]._.extend.protocol_handlers.sub (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/ddp.js:1410:12)
I20150707-10:23:10.084(-4)?     at [object Object].MeteorX.Session.protocol_handlers.sub (/Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/meteorhacks_unblock.js:23:15)
I20150707-10:23:10.084(-4)?     at /Users/patricklewis/Documents/sites/meteor/bace/app/.meteor/local/build/programs/server/packages/ddp.js:1374:43

I have a feeling it has to do the fact that I have a check for if you are logged in in the publish function like so

Meteor.publishComposite('project', function (_id) {
  if(!this.userId)
    return;

Any ideas?

Return empty object or null cursor

Is there a way for a find function to return an intentionally empty set of documents? For example, I have a parent publication retrieving the User document and a child find function returning a cursor only if the User document contains the requisite permission.

If the child find function is passed an invalid User document, there's currently no good way to process that. When using Meteor.publish, we can return an empty set of values as an empty Array or simply by calling this.ready() if the parent subscription doesn't check out. That don't appear to work within Meteor.publishComposite and result in the follow traceback instead:

I20141105-22:52:42.905(0)? Exception from task: TypeError: Object  has no method '_getCollectionName'
I20141105-22:52:42.907(0)?     at Publication._getCollectionName (packages/reywood:publish-composite/publish_composite.js:171)
I20141105-22:52:42.908(0)?     at Publication.publish (packages/reywood:publish-composite/publish_composite.js:105)
I20141105-22:52:42.909(0)?     at null.<anonymous> (packages/reywood:publish-composite/publish_composite.js:180)
I20141105-22:52:42.910(0)?     at Array.forEach (native)
I20141105-22:52:42.910(0)?     at Function._.each._.forEach (packages/underscore/underscore.js:105)
I20141105-22:52:42.911(0)?     at Publication._publishChildrenOf (packages/reywood:publish-composite/publish_composite.js:177)
I20141105-22:52:42.911(0)?     at Object.observeHandle.cursor.observe.added (packages/reywood:publish-composite/publish_composite.js:118)
I20141105-22:52:42.912(0)?     at observeChangesCallbacks.added (packages/minimongo/observe.js:153)
I20141105-22:52:42.913(0)?     at self.applyChange.added (packages/minimongo/observe.js:53)
I20141105-22:52:42.914(0)?     at packages/mongo/observe_multiplex.js:188
I20141105-22:52:42.944(0)? Exception from sub PLdN4pDMc5NfWi82h TypeError: Object  has no method '_getCollectionName'
I20141105-22:52:42.944(0)?     at Object.Future.wait (/home/vagrant/.meteor/packages/meteor-tool/.1.0.35.ftql1v++os.linux.x86_64+web.browser+web.cordova/meteor-tool-os.linux.x86_64/dev_bundle/lib/node_modules/fibers/future.js:326:15)
I20141105-22:52:42.945(0)?     at _.extend.runTask (packages/meteor/fiber_helpers.js:79)
I20141105-22:52:42.946(0)?     at _.extend.addHandleAndSendInitialAdds (packages/mongo/observe_multiplex.js:47)
I20141105-22:52:42.946(0)?     at MongoConnection._observeChanges (packages/mongo/mongo_driver.js:1108)
I20141105-22:52:42.947(0)?     at Cursor.observeChanges (packages/mongo/mongo_driver.js:783)
I20141105-22:52:42.947(0)?     at Function.LocalCollection._observeFromObserveChanges (packages/minimongo/observe.js:177)
I20141105-22:52:42.947(0)?     at Cursor.observe (packages/mongo/mongo_driver.js:777)
I20141105-22:52:42.948(0)?     at Publication.publish (packages/reywood:publish-composite/publish_composite.js:108)
I20141105-22:52:42.948(0)?     at null._handler (packages/reywood:publish-composite/publish_composite.js:12)
I20141105-22:52:42.948(0)?     at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1599)
I20141105-22:52:42.949(0)?     - - - - -
I20141105-22:52:42.950(0)?     at Publication._getCollectionName (packages/reywood:publish-composite/publish_composite.js:171)
I20141105-22:52:42.951(0)?     at Publication.publish (packages/reywood:publish-composite/publish_composite.js:105)
I20141105-22:52:42.951(0)?     at null.<anonymous> (packages/reywood:publish-composite/publish_composite.js:180)
I20141105-22:52:42.952(0)?     at Array.forEach (native)
I20141105-22:52:42.953(0)?     at Function._.each._.forEach (packages/underscore/underscore.js:105)
I20141105-22:52:42.954(0)?     at Publication._publishChildrenOf (packages/reywood:publish-composite/publish_composite.js:177)
I20141105-22:52:42.955(0)?     at Object.observeHandle.cursor.observe.added (packages/reywood:publish-composite/publish_composite.js:118)
I20141105-22:52:42.956(0)?     at observeChangesCallbacks.added (packages/minimongo/observe.js:153)
I20141105-22:52:42.957(0)?     at self.applyChange.added (packages/minimongo/observe.js:53)
I20141105-22:52:42.958(0)?     at packages/mongo/observe_multiplex.js:188

Aurgument check

Hi,

It would be nice if this package would oblige us to check the arguments to the publish function like we have to unwed Meteor.Publish with audit-argument-checks installed.

Exception in queued task: TypeError: Object has no method '_getCollectionName'

Exception in queued task: TypeError: Object has no method 'getCollectionName'
at Publication.getCollectionName (packages/reywood:publish-composite/lib/publication.js:74:1)
at Publication.publish (packages/reywood:publish-composite/lib/publication.js:15:1)
at Publication.createChildPublication (packages/reywood:publish-composite/lib/publication.js:81:1)
at Array.forEach (native)
at Function.
.each.
.forEach (packages/underscore/underscore.js:105:1)
at Publication._publishChildrenOf (packages/reywood:publish-composite/lib/publication.js:78:1)
at Object.added (packages/reywood:publish-composite/lib/publication.js:30:1)
at [object Object].observeChangesCallbacks.added (packages/minimongo/observe.js:153:1)
at self.applyChange.added (packages/minimongo/observe.js:53:1)
at packages/mongo/observe_multiplex.js:183:1

Multiple cursors

In Meteor's regular publish function I can return an array of cursors for different collections. Is there a way to do this with publishComposite?

Overlapping child documents are not published to all their named collections

When creating multiple child collections that have a collectionName (so they end up in virtual collections), overlapping documents (docs that should appear in both virtual collections) only appear in one of the virtual child collections.

This is not an issue when you're not using the collectionName, since they you're always finding in the real mongo collection, and everything will be present there.

[TypeError: Object [object Object] has no method 'publishComposite']

Hi!

I have an application that, until now, has relied on reactivity on the client to update subscribtions that are dependent on other collections. This is working, but it seems as a rather hacky solution. After reading a bit on the reactive publications topic I came across this package and it seems very promising.

Unfortunately, I am very quickly running into a problem. I have added the reywood:publish-composite package to my meteor application and added a call to Meteor.publishComposite() inside a file called publications.js under the server/ folder in my application.

Meteor.publishComposite('allBids', function(game_id){
  return {
    find: function(){
      return Games.find({_id:game_id});
    },
    children: [
      {
        find: function(game){
          if (game.round_started){
            return Bids.find({'game_id':game._id, 'round':game.current_round});
          }
        }
      }
    ]
  }
});

Here I am trying to accomplish a reactive publish of the Bids collection when the field 'round_started' of a game is changed. I do not think this has any relevance to the issue, but just to be sure.

The console prints out this error:

publications.js" has syntax errors. [TypeError: Object [object Object] has no method 'publishComposite']

It seems the publishComposite function is not added to the Meteor namespace. Do I have to do anything special in order to set this up? I could not find anything in the README.

Am I doing something wrong here?

My meteor packages are:

accounts-password            1.0.4  Password support for accounts
email                        1.0.4  Send email messages
ian:accounts-ui-bootstrap-3  1.1.20  Bootstrap-styled accounts-ui with multi-language support.
ian:bootstrap-3              3.3.0_2  HTML, CSS, and JS framework for developing responsive, mobile first projects on the web.
iron:router                  1.0.1  Routing specifically designed for Meteor
reywood:publish-composite    1.3.3  Publish a set of related documents from multiple collections with a reactive join
sacha:spin                   2.0.4  Simple spinner package for Meteor
sanjo:jasmine                0.5.0  Easily use Jasmine in Meteor
standard-app-packages        1.0.3  Moved to meteor-platform
velocity:html-reporter       0.3.0-rc.3  Reactive Velocity test reports in your app.

Thanks,

Kjetil

Problem with unset

When i do Collection.update({....},{$unset: {field: ''}}) subscription does not send this change.

This is because when you call changed callback on subscription you need to set fields that were unset as undefined (document must be object with this property explicitly set as undefined not just object without this property). Link to meteor docs http://docs.meteor.com/#publish_changed.

observeChanges() works that way by default but observe() just send you old and new document so you need to manually check if field no longer exist in new doc.

PS. i sent PR with fix

Cancel publish

Within the normal publish method there is an easy way to cancel the publish and return nothing (just use this.ready(); return;. With publishComposite this doesn't work. I get the following exception then: Exception from sub 2BgTTyL3mgoTmRtbL TypeError: Cannot read property 'children' of undefined.

How could I just cancel the publish (and publish nothing), for example when some provided parameter is invalid?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.