mongodbmeteorpublish-subscribemeteor-publications

Meteor-publish returns more rows then required from MongoDB


I have a collection:

{
    "_id" : "SeGtBvCT7ojF2v5x9",
    "teamId" : "d74JJ9s5k6tijeQaz",
    "userScores" : [ 
        {
            "userId" : "6ghphqzx9GFnvKYKY",
            "scores" : 10,
            "addedAt" : ISODate("2019-02-04T06:37:06.387Z")
        }, 
        {
            "userId" : "56ghp45hqzx9G2dda",
            "scores" : 1,
            "addedAt" : ISODate("2019-02-04T06:37:19.105Z")
        }, 
        {
            "userId" : "wrr3422fwefx6fFGs",
            "scores" : 4,
            "addedAt" : ISODate("2019-02-04T06:37:44.005Z")
        }
    ]
}

I need to return 'userScores' for one teamId and current user Id (this.userId). So I made this publish method.

Meteor.publish('scoresTeamByUser', function(teamId) {
  return Scores.find(
      { teamId }, 
      { userScores: { $elemMatch: { userId: this.userId } } }
  );
});

But in meteor/react app I receive (this.props.receivedScores) the whole document, with all rows in "userScores".

export default withTracker(props => {
    const scoresSubscription = Meteor.subscribe('scoresTeamByUser', props.teamId);
    return {
        receivedScores: Scores.findOne(),
        scoresLoaded: scoresSubscription.ready()
    };
})(GiveScores);

How to get just data for one team and one user which gave a score? Thanks :)


Solution

  • I checked your query and it works fine and returns only one object of the userScores array that matches the userId.

    You need to use fields to filter the fields that you want to publish.

    Meteor.publish('scoresTeamByUser', function(teamId) {
      return Scores.find(
          { teamId }, 
          { fields: { userScores: { $elemMatch: { userId: this.userId }}} }
      );
    });
    

    The reason that you are getting all the objects in the userScores array is that you must be having another subscription that is publishing the entire record. You can check this by console.log(Scores.findOne({ props.teamId})) before subscribing to the scoresTeamByUser publication.

    So, you have to either find that publication and limit it to publish only the scores of the current user or in your current subscription, you have to filter the data on the client-side query as below.

    export default withTracker(props => {
        const scoresSubscription = Meteor.subscribe('scoresTeamByUser', props.teamId);
        return {
            receivedScores: Scores.findOne({ teamId: props.teamId }, 
      { userScores: { $elemMatch: { userId: Meteor.userId() } }),
            scoresLoaded: scoresSubscription.ready()
        };
    })(GiveScores);