[ Solved ] findOne executed in meteor methods dosen't works

In the next line the query dosen’t work, but in other metheor methods works:

const candidato = Candidatos.findOne({propietario: this.userId});

Note 1: The methods works and the query works.

File: methods.js

export const registrar = new ValidatedMethod({
    name: 'postulaciones.registrar',
    mixins: [LoggedInMixin],
    checkLoggedInError: {
        error: 'noLogeado',
        message: 'Para postularse en una vacante necesitas registrarte y/o iniciar sesión.',
        reason: 'Usuario no logeado'
    },
    validate: new SimpleSchema({
        vacanteId: {type: String}
    }).validator(),
    run({vacanteId}) {
        const candidato = Candidatos.findOne({propietario: this.userId});
        console.log('candidato ', candidato);
        const postulacion = {
            vacanteId: vacanteId,
            candidatoId: candidato._id,
            estado: 1
        };
        return Postulaciones.insert(postulacion);
    }
});

I suggest this is not what you think it is. Why don’t you add a debug console.log(this) to check?

Hello. Thanks for read.

  • the query works
  • the Method works

but when I put the query inside in method don’t works

this.userId only works inside publication code. I think you have to use Meteor.userId() in methods.

I do not believe that is correct. Every method on the server has the userId in the this context.

For example the following method allows to retrieve the username for any entry in Meteor.users if the requesting user has role admin

Meteor.methods({
  user_name: function(id) {
    if(this.isSimulation) {
     // stub method runs on client and message will be in the browser console
     console.log('user_name for '+id+' called by '+this.userId);
    } else {
     // the following will be in the server console
     console.log('user_name for '+id+' called by '+this.userId);
     if (Roles.userIsInRole(this.userId, ['admin'])) {
      return Meteor.users.findOne({ _id: id }).username;
     } else {
      throw new Meteor.Error(403, 'Access Denied', 'You must be member of the group admin');
     }
    }
  }
});

Meteor.call('user_name', <some id>, function(err, user_name) {
 if(err) console.error(err);
 else console.log(user_name);
});

The question is if your Method runs on the client (the stub) and your collection doesn’t contain the requested record.

Hello. Thanks for read.

the Meteor.userId and this.userId are the same, isn’t the point.

Why when i will use a property to my object “candidato” print undefined?.

If i print console.log(candidato); works!. But when i use a one propertycandidato console.log(candidato.whatever_property) it does not work.

Yeah sorry, I checked out the guide for validated methods and they are doing the same thing.

@zxcvbnm1234567890 Sorry, I can’t tell from your code what the problem is. If you could create a small repro isolating the problem I could take a shot at debugging it.

Hello, thanks for read.
The meteor method code registrar is in the top of this post.

This is the code client. The call of registrar meteor method is inside of postularme method.

main libraries versions:

angular meteor @1.3.X
angular @1.5.X
meteor @1.4.1
validate metthod @1.1
mongodb @3.2.X

I hope that this information will be relevant for you:

import angular from "angular";
import angularMeteor from "angular-meteor";
import uiRouter from "angular-ui-router";
import "./vacanteDetalle.html";
import {Vacantes} from "../../../../api/vacantes/collection.js";
import {registrar} from '../../../../api/postulaciones/methods.js';
import {Counts} from 'meteor/tmeasday:publish-counts';

class VacanteDetalle {
    constructor($stateParams, $scope, $reactive) {
        'ngInject';
        $reactive(this).attach($scope);

        this.respuesta = {};
        this.helpers({...},
            postulado(){...}
        });
    }

    postularme() {
        registrar.call({vacanteId: this.vacanteId}, (error, result)=> {
            if (error) {...} else {...}

        })
    }
}

const name = 'vacanteDetalle';

export default angular
    .module(name, [
        angularMeteor,
        uiRouter
    ])
    .component(name, {...})
    .config(config);

function config($stateProvider) {
    'ngInject';

    $stateProvider
        .state('demos.vacantes.detalle', {...});
}

Be careful when you fetch data in methods, if the method is shared by client and server.

On the client Candidatos.findOne({propietario: this.userId}); may return undefined, because the data might not be published there. On the server this should always return a result (if the document exists, of course).

So check what’s happening on the server and ignore the client. Maybe even wrap the content of run inside a if(Meteor.isServer)

Edit: As a rule of thumb, i would say: if you use find or findOne in a method, declare this part only on the server. If you need latency compensation, try to write a client-stub, that works without this related data (from find).

1 Like

Hello, thanks for reply and read
Ok, but In the meteor guide, next link, line 30
why in the meteor exaple they dont use if(Meteor.isServer) and works?

https://github.com/meteor/todos/blob/master/imports/api/lists/methods.js line 30
https://github.com/meteor/todos/blob/master/imports/ui/components/lists-show.js line 89

again, thanks for reply!

If you declare methods on client and server, the client does a simulation for latency compensation and the server will compute the real value. If the server will have a different result, the client will revert the simulation and update everything with the server-value.

This works properly, when you do just an insert. It mostly works, when you fetch other data in your method, as long as this data is published. In the Todo- example that you linked, it fetches the List-document from the given listId. So it’s likely that this document is already published.

But if you do more complex logic with more data in your method, you risk that the client-stub will often return a different result than the server due to missing data and therefore latency compensation no longer works. If the client-simulation will throw an error because of missing data, the method will not be called on the server as far as i remember.

To come back to your initial question: what is logged by the client and by the server in console.log('candidato ', candidato); ? If candidato is undefined on the client, the next line will crash (Because of candidato._id). If so, you should either guarantee that this data is published (hard), do the logic only on the server (wrap it in if (Meteor.isServer), or catch the case where candidat is undefined on the client (you could therefore just ommit candidatoId in the document until the server reports the correct result)

1 Like

Hello @macrozone, thanks for answer.

IT WORKS!

I wrap the code inside meteor.isServer() and now I can to access to a any property of the object

Now I will to read more about simulation latency compensation client for and the server compute real value.

thanks for your advise
Like!