[SOLVED] Errors with Meteor Methods or PUB/SUB

This is my publish function:

Meteor.publish('coinbaseinfo', function() {
        if (this.userId) {
            return Meteor.users.find({
                _id: this.userId
            }, {
                fields: {
                    'services.coinbase.name': 1,
                    'services.coinbase.email': 1,
                }
            });
        } else {
            this.ready();
        }
    });

This is where I’m calling my info for the client side template:

Template.finishCoinbase.onCreated(function userProfile() {
    Meteor.subscribe('coinbaseinfo');
    const info= Meteor.users.find({_id: Meteor.userId()}, {
        fields: {
            'services.coinbase.name': 1,
            'services.coinbase.email': 1,
        }
    });
    console.log(info);
    return info;
});

Im trying to retrieve certain fields from a user’s document from Mongo.

This is what the console.log is giving me :

Cursor {collection: LocalCollection, sorter: null, matcher: Matcher, _selectorId: "sYm6R2ZqJvpyFyZbj", skip: 0, …}
collection
:
LocalCollection {name: "users", _docs: _IdMap, _observeQueue: M…r._SynchronousQueue, next_qid: 25, queries: {…}, …}
fields
:
{services.coinbase.name: 1, services.coinbase.email: 1}
limit
:
undefined
matcher
:
Matcher {_paths: {…}, _hasGeoQuery: false, _hasWhere: false, _isSimple: true, _matchingDocument: undefined, …}
reactive
:
true
skip
:
0
sorter
:
null
_projectionFn
:
doc => {…}
_selectorId
:
"sYm6R2ZqJvpyFyZbj"
_transform
:
null
__proto__
:
Object

How do I get just the fields i am asking for.

You’re getting a cursor back from that query. Instead of using find() use findOne()
Also, if your only parameter is the_id you don’t need to specify it as an object, you can just pass it as a single variable like this:

const info= Meteor.users.findOne(Meteor.userId(), { ...

Although to be honest you shouldn’t use a subscription for this sort of transaction. Write a method/call to get it from the server. This sort of data doesn’t need to be subscribed to…

I tried using methods but they aren’t exactly working either. This is my method call:

findCoinbaseinfo:() => {
        return Meteor.users.findOne(Meteor.userId(), {
            fields: {
                'services.coinbase.name': 1,
                'services.coinbase.email': 1,
            }
        });
    }

This is my template helper code:

Template.finishCoinbase.helpers(function userProfile() {
    Meteor.call('findCoinbaseinfo', function(error, result){
        if(error){
            alert('Error');
        }else{
            Session.set('info', result)
        }
    });
    return Session.get('info')
});

Now I am calling this template helper to fill out the field of the form. I am calling it with blaze

<div class='row'>
                    <div class="input-field col s12">
                        <input value={{userProfile.name}} id="name" type="text" class="validate" autocomplete="on">
                        <label class="active" for="name">Enter Your Name</label>
                    </div>
                </div>
                <div class='row'>
                    <div class="input-field col s12">
                        <input value={{userProfile.email}} id="email" type="email" class="validate" autocomplete="off">
                        <label for="email">Enter Your Email</label>
                    </div>
                </div>

Isnt exactly working, i dont think its being passed from the method at all or I am not calling it properly from the blaze handlebar.

In method calls you can’t use Meteor.userId().
You need to use this.userId instead :+1:t3:

Check the docs, methods are a bit different in how they handle the “current” user.

I thought this.userId was only required for only publish functions.
Regardless I changed the code and put this.userId but I still get no results :disappointed_relieved:

Ah yeah I see why but I don’t think I know the best way to fix it.

Template.finishCoinbase.helpers(function userProfile() {
    Meteor.call('findCoinbaseinfo', function(error, result){
        if(error){
            alert('Error');
        }else{
            Session.set('info', result) // <--- this actually happens after you've already returned out from this function.
        }
    });
    return Session.get('info') // <--- this fires before the session has been updated
});

I haven’t used Blaze in a long while so not sure the best way to get around this. Maybe someone who uses Blaze can help out.

Template.finishCoinbase.helpers(function userProfile() {
    Meteor.call('findCoinbaseinfo', function(error, result){
        if(error){
            alert('Error');
        }else{
            Session.set('info', result) // <--- this actually happens after you've already returned out from this function.
        }
        return Session.get('info') // <--- this fires before the session has been updated
    });
});

Isn’t this working ? just to return the Session info inside your Meteor.call ? just a hint, didn’t have time to try.

Yeah I wasn’t sure if that would work. don’t remember enough about template helpers!

Before choosing between Meteor methods and pub/sub, you need to ask yourself whether you want to work with a snapshot of data, or live data. Obviously, you can repeatedly request snapshots, but these all need to be initiated from the client. In such cases, perhaps pub/sub would be a better choice.

If it’s a snapshot, then methods are the better choice, otherwise you need pub/sub.

(Incidentally, you can use Meteor.user and Meteor.userId in methods from v1.5.1)

As far as using methods with Blaze, the recommended practice for a “one-time” snapshot is to make the call in the Template#onCreated, since this always runs once for each template instance.

You should avoid getting and setting the same reactive variable in the same reactive context (such as a template helper). It’s a recipe for an infinite loop unless you’re very careful.

This is a bit of generic-ish template code which will reactively update the client when the method data becomes available:

Template.templateName.onCreated(function templateNameOnCreated() {
  this.info = new ReactiveVar();
  Meteor.call('methodName', (error, result) => {
    if (error) {
      alert('Error');
    } else {
      this.info.set(result);
    }
  });
});

Template.templateName.helpers({
  info() {
    return Template.instance().info.get();
  },
});

By the way, your method is electing to return only the fields you have identified (plus the _id field), which I’m not sure is your intention.

1 Like

The above solution seemed to have done the trick Exactly what I was looking for.

1 Like