Search code examples
apostrophe-cms

Redefine join projections on the fly when using cursors


Is it possible to edit which fields of a joined piece get loaded when using the find cursor? For example, using the apostrophe-samples project, I've edited the product piece join to specialists by adding the following projection:

...
    {
      name: '_specialists',
      type: 'joinByArray',
      withType: 'specialist',
      label: 'Specialists',
      help: 'The right people to ask about this product.',
      filters: {
        projection: {
          title: 1
        }
      }
    }
...

Somewhere else, I'm using find to fetch some products, but in this case I do need more data from the related specialists. Is there a way to tell Apostrophe "hey, this time also get me THESE fields from the join" rather than making the original projection more permissive or doing it in 2 steps (first querying the products for the specialists ids and then querying for the whole specialists)?

For example, I tried this:

    self.modulesReady = function() {
      var req = self.apos.tasks.getAnonReq();
      self.apos.docs.getManager('product').find(req, {}, {title:1, specialistsIds:1, _specialists: {slug: 1}}).toArray(function(err, pieces) {
        // do something
      })
    },

But it still only returns the specialists' titles as defined in the original join projection.


Solution

  • Currently this is not possible in an elegant way. The filters configured for a join are invoked just before toArray is invoked for the query that fetches the join, which means there is currently no opportunity to override them. See the implementation of the joinDriver method:

    https://github.com/apostrophecms/apostrophe/blob/master/lib/modules/apostrophe-schemas/index.js#L590-L599

    You could of course re-fetch the joined documents after your query, but that isn't a great solution.

    An implementation that allowed for this would involve upgrading the withJoins option, which can be used to override which joins are performed at all by passing an array of join names, to also support including objects in that array. Those objects could feature both a join name (or join dot path) and overrides for cursor filters. This would then have to be propagated through to joinDriver without introducing bc breaks, which is possible since the methods involved do take an options argument.