0

This is an example of documents which are assigned together by a parent-field:

{
    "_id" : "dUgyVgoxVhYOU0wZC",
    "title" : "section-title",
    "type" : "section",
    "parent" : "I5ChGoVOeU2BKsgvZ"
}
{
    "_id" : "G3ecqJxydXJnFvRhN",
    "title" : "group-title",
    "type" : "group",
    "parent" : "dUgyVgoxVhYOU0wZC"
}
{
    "_id" : "djM5IU2wmOhpGoBX8",
    "title" : "elemtn-title",
    "type" : "element",
    "parent" : "G3ecqJxydXJnFvRhN"
}

Now I need all the docs, which are assigned together. My attempt:

var id = "dUgyVgoxVhYOU0wZC";

Meteor.publish('article', function(id) { 
    return Articles.find({ 
        $or: [ 
            { _id: id }, 
            { parent: id } 
        ]  
    }); 
});

But this just goes to the second level. But I also need the third level for which I don't have the direct access (id or parent)

Update

I tried to do that with publishComposite, but my attempt doesn't work:

Meteor.publishComposite('article', function(id){
    return {
        find: function(){
            return Articles.find({ 
                $or: [ 
                    { _id: id }, 
                    { parent: id } 
                ]  
            });
        },
        children: [{
            find: function(element){
                return Article.find({ parent: element._id });
            }
        }]
    }
 });
user3848987
  • 1,627
  • 1
  • 14
  • 31

1 Answers1

2

Here are some possible solutions depending on your requirements:

If reactivity in the articles is important but not in the structure

In other words, if a title changes you want the client to see that immediately, but if a 4th-level child is added it's okay if the client doesn't see the change without resubscribing.

In this case you can traverse the tree once and publish all of the related ids. Here's an example implementation:

Meteor.publish('article', function(articleId) {
  var ids = [];

  // recursive search for child articles - populates
  // the ids array
  var search = function(id) {
    ids.push(id);
    var children = Articles.find({parent: id}).fetch();
    _.each(children, function(child) {
      search(child._id);
    });
  };

  // populate ids, starting with articleId
  search(articleId);

  return Articles.find({_id: {$in: ids}});
});

If reactivity in the structure is important and the maximum depth is small

For example, if you know that you will always get at most three levels then you can use a library to compute a reactive join. Have a look at publish-composite.

If reactivity in the structure is important and the depth is unknown

The only straightforward way to deal with this case is to restructure your article data. For example:

{
  _id: "dUgyVgoxVhYOU0wZC",
  title: "section-title",
  type: "section",
  children: [
    {
      _id: "G3ecqJxydXJnFvRhN",
      title: "group-title",
      type: "group",
      children: [
        {
          _id: "djM5IU2wmOhpGoBX8",
          title: "elemtn-title",
          type: "element"
        }
      ]
    }
  ]
};

By publishing the entire document you can always be guaranteed that the structure is maintained. Of course this may not be practical in your particular use case.

David Weldon
  • 63,632
  • 11
  • 148
  • 146