1

How to publish single objects seems not clear enough to me. Please what's the best way to handle this. This code snippet does not display anything on the view.

Helper file

singleSchool: function () {
   if (Meteor.userId()) {
      let myslug = FlowRouter.getParam('myslug');
      var subValues = Meteor.subscribe('SingleSchool', myslug );
        if (myslug ) {
          let Schools = SchoolDb.findOne({slug: myslug});
          if (Schools && subValues.ready()) {
             return Schools;
          }
       }
   }    
},

Publish file

Meteor.publish('SingleSchool', function (schoolSlug) {
  check( schoolSlug, Match.OneOf( String, null, undefined ) );
    user = Meteor.users.findOne({_id:this.userId})
  if(user) {
    if(user.emails[0].verified) {
      return SchoolDb.findOne({ slug: schoolSlug, userId: {$lt: this.userId}});
    } else {
      throw new Meteor.Error('Not authorized');
      return false;
    }
  }
});

template file

<template name="view">
  {{#if currentUser}}
    {{#if Template.subscriptionsReady }}
      {{#with singleSchool}}
        {{singleSchool._id}}
        {{singleSchool.addschoolname}}
      {{/with}}
    {{/if}}
  {{/if}}
</template>
Jankapunkt
  • 8,128
  • 4
  • 30
  • 59
ken4ward
  • 2,246
  • 5
  • 49
  • 89
  • 1
    You should consider moving the subscription within your helper function to a lifecycle method of the Template `view` instead. You're also double checking (both in the subscription and in the template) if you're logged in - were you logged in while testing this? – chazsolo Sep 26 '17 at 12:58
  • what is `userId: {$lt: this.userId}`? – Ankur Soni Sep 26 '17 at 13:02
  • @Ankur, it is to use it has a second filter to the slug passed from the url. According to Mongo doc it simply mean `SELECT * FROM inventory WHERE status = "A" AND qty < 30`, which is what I want. It should only publish the records created by the user. https://docs.mongodb.com/manual/tutorial/query-documents/ – ken4ward Sep 26 '17 at 13:05
  • @kehinde: is it Number or string?? I hope it is Number stored in mongoDB like `"userId" : 12` – Ankur Soni Sep 26 '17 at 13:09
  • MongoDb stores it _id as strings. It is different from RDBMS. – ken4ward Sep 26 '17 at 13:10
  • 1
    What are you trying to do with that `$lt` filter? `$lt` means less than. I don't know how your `userId` string is going to be less than another `userId` string or ever match the current user!? Leave it out and let it filter for an exact match – coagmano Sep 27 '17 at 06:47
  • @Fred, that was exactly the culprit. You spotted it. Appreciate a bunch. – ken4ward Sep 27 '17 at 09:36

2 Answers2

4

As you said "This code snippet does not display anything on the view." well, inside Meteor.publish you need to return cursor, not array or any other object.

So use this code:

Meteor.publish('SingleSchool', function (schoolSlug) {
  check( schoolSlug, Match.OneOf( String, null, undefined ) );
  var user = Meteor.users.findOne({_id:this.userId});
  if(!user || !user.emails[0].verified) {
        throw new Meteor.Error('Not authorized');
    }
    return SchoolDb.find({ slug: schoolSlug, userId: {$lt: this.userId}},{limit:1});
});

I would definitely recommend you to go through How to avoid Common Mistakes

Ankur Soni
  • 5,725
  • 5
  • 50
  • 81
1

When I am concerned only for a single object, I implement this using a meteor method:

Meteor.methods({
    "getSingleSchool":function(schoolSlug) {
        //... check args and user permissions
        return SchoolDb.findOne({ slug: schoolSlug, userId: {$lt: this.userId}});
    },
});

Then in the template I run this method in the onCreated autorun part:

Template.view.onCreated(function(){
    const instance = this;
    instance.state = new ReactiveDict();

    instance.autorun(function(){
        let my slug = FlowRouter.getParam('myslug');

        // load if no loaded yet
        if (my slug && !instance.state.get("singleSchool")) {
            Meteor.call("getSingleSchool", mySlug, function(err, res){
                //handle err if occurred...
                this.state.set("singleSchool", res);
            }.bind(instance)); //make instance available
        } 

    });
});

The helper then just returns a value, if the school is loaded:

singleSchool: function () {
   return Template.instance().state.get("singleSchool");   
},
Jankapunkt
  • 8,128
  • 4
  • 30
  • 59