Publications getting confused inside container: react-komposer [Solved]


#1

Hi,

Very odd behaviour which I’m not sure how to troubleshoot.

Have a container as below

import { composeAll, composeWithTracker } from 'react-komposer';
import { Loading } from '../components/layout/loading.js';
import { Meteor } from 'meteor/meteor';

import { Entities } from '../../api/entities/entities.js';
import { Groups } from '../../api/groups/groups.js';

import { LocalAdmin } from '../components/localAdmin/localAdmin.js';

const composerUser = (params, onData) => {
	onData(null, { user: Meteor.user() });
};

const composerEntities = (params, onData) => {
  const subscription = Meteor.subscribe('entities.localAdmin');
  if (subscription.ready()) {
    const entities = Entities.find().fetch();
    onData(null, { entities });
  }
};

const composerGroups = (params, onData) => {
  const subscription = Meteor.subscribe('groups.localAdmin');
  if (subscription.ready()) {
    const groups = Groups.find().fetch();
    onData(null, { groups });
  }
};


export default composeAll(
  composeWithTracker(composerUser, Loading, null, { pure: false }),
  composeWithTracker(composerEntities, Loading, null, { pure: false }),
  composeWithTracker(composerGroups, Loading, null, { pure: false }),
)(LocalAdmin);

The two publications look like below:

Meteor.publish('entities.localAdmin', function() {
  let tempEntities = [];

  // The idea is work out the original entity id and add to array.
  // Then also add in any entities which are linked to the original.
  if (Entities.find({ entityUsers: this.userId }, { _id: 1 }, { limit: 1 }).fetch().length) {
    const entity = Entities.findOne({ entityUsers: this.userId });
    tempEntities.push(entity._id);
    entity.entityLinkages.map((x) => (
      tempEntities.push(x)
    ));
  }

  // Publish the lot, the $in parses for entities in our dynamic array
  return Entities.find({ _id: { $in: tempEntities } });
});

And…

Meteor.publish('groups.localAdmin', function() {
  let groups = [];

  // The idea is work out the original entity id
  // Then check what groups it has and make up list of same..
  if (Entities.find({ entityUsers: this.userId }, { _id: 1 }, { limit: 1 }).fetch().length) {
    const entity = Entities.findOne({ entityUsers: this.userId });
    entity.entityGroups.map((x) => (
      groups.push(x)
    ));
  }

  // Publish the lot, the $in parses for groups in our dynamic array
  return Groups.find({ _id: { $in: groups } });
});

If I take out the composerGroups from my container, the entities publications works perfectly. If I leave it in, the entities publication seems to break and provide me with more information than needed.

Inside my UI component LocalAdmin, in the componentWillMount() I have three consoles…

componentWillMount() {
  console.log(this.props.user);
  console.log(this.props.entities);
  console.log(this.props.groups);
}

Output
(1) Leave the composerGroups out… ignore the proptype warning, its just I had isRequired on the props… Note that the localAdmin.js:20 has “2/two” objects

warning.js:44 Warning: Failed prop type: Required prop `groups` was not specified in `LocalAdmin`.
localAdmin.js:19 Object {_id: "MJF2P9JW6Y2bXAqtp", emails: Array[1], profile: Object, roles: Object}
localAdmin.js:20 [Object, Object]
localAdmin.js:21 undefined

(2) Keep the composerGroups in… Note that the localAdmin.js:20 has “4/four” objects

localAdmin.js:19 Object {_id: "MJF2P9JW6Y2bXAqtp", emails: Array[1], profile: Object, roles: Object}
localAdmin.js:20 [Object, Object, Object, Object]
localAdmin.js:21 [Object, Object, Object, Object]

That is the problem. The correct functioning of the publish should have 2 objects only. Somehow the publications are getting confused.

To clarify, as far as I can tell the publications themselves are fine. But when the get into the container together, they seem to shit themselves.

How do i troubleshoot this? Thanks so much.

Tat


#2

Ok, so this really does not make any sense…

I removed all the code from the entities publish, leaving… well, null should go back right?

Meteor.publish('entities.localAdmin', function() {
  let tempEntities = [];
  return Entities.find({ _id: { $in: tempEntities } });
});

There is absolutely no difference in what the container is publishing? So then I put in a console.log in my container…

const composerEntities = (params, onData) => {
  const subscription = Meteor.subscribe('entities.localAdmin');
  if (subscription.ready()) {
    const entities = Entities.find().fetch();
    console.log(entities); // THIS IS THE CONSOLE.LOG()
    onData(null, { entities });
  }
};

Giving:

localAdminContainer.js:18 [Object, Object, Object, Object]

How can my subscription have all the information, when I have not published anything? Am I missing something really basic?

Thanks so much.

Tat


#3

maybe you have autopublish still in your meteor-packages?

Or you have another container that subscribes to any Entities.
Be careful that collections are always global in your client. So if you do a Entities.find().fetch(), you will receive any entities that you have in your local collection.


#4

@macrozone - well it sounds like it would be point 2. I am unfamiliar with the concept. Can you please elaborate? How can i recieve any entities, I’m logging in and out when i chnage users to test, and publishes are on roles?


#5

@macrozone - I worked this out, thank you so much for the tip. It was that i was receiving Entities from another container.

  1. I was receiving Entities in my LocalAdmin component as above.
  2. I was also recieving Entities in my Nav component which caused the clash.

The fix was to simply put in the same filtering on the publish which the nav component was using as the filtering on the localAdmin publish.

Thanks so much - it confused me quite a bit for a while.

Tat


#6

Indeed, its not that intuitive anymore with the container-pattern. The subscription pattern was a good fit in the earlier days of meteor with blaze. The global nature of it made it really simple to use, but with the newer component-driven-approaches of react with containers, it starts to feel awkward.

That’s one reason why Meteor moves to a new data-layer called apollo in the future, which seems to be a better fit for the container/component-pattern. (With react-komposer and mantra it should be fairly easy to switch slowely to apollo if needed, so no worries about that).