6
votes

i'm working on a Meteor project, and I must say that isn't easy at all, especially for one thing: callbacks !

Everything is async, so I wonder how do I must do to get results from my mongodb.

var user = Meteor.users.findOne({username: "john"});
return (user); // sometimes returns "undefined"

...

var user = Meteor.users.findOne({username: "john"});
if (user)                    // so ok, I check if it exists!
    return (user);           // Cool, I got my user!
return ();                   // Ok and what should I return here? I want my user!

I don't want to be dirty and put like setTimeout everywhere. Anybody has a solution for this ?


EDIT : I noticed in router.js with console.log that my data is returned 4 times. 2 times with an undefined value and 2 other times with the expected value. In the view, it's still undefined. Why the router passes like 4 times in this route ? Does it display the first result of the return value in the router ?

What should I return if the find() doesn't find anything ?


EDIT 2: Here is some code to understand.

this.route('profilePage', {
    path: 'profil/:_id?',
    waitOn: function() {
        return [
        Meteor.subscribe('article', { prop: this.params._id}), // id can be id or username
        Meteor.subscribe('article', { userId: this.params._id}), // id can be id or username
        Meteor.subscribe('params'),
        Meteor.subscribe('profil', (this.params._id ? this.params._id : Meteor.userId()))
        ];
    },
    data: function() {
        if (this.params._id) {
            var user = Meteor.users.findOne(this.params._id);
            if (!user)
                user = Meteor.users.findOne({username: this.params._id});
            console.log(user);
            return user;
        }
        else if (Meteor.userId())
            return Meteor.user();
        else
            Router.go("userCreate");
    }
});

I get this on the console: http://puu.sh/debdJ/69419911f7.png

(text version following)

undefined
undefined
Object_id: "o3mgLcechYTtHPELh"addresses: (....)
Object_id: "o3mgLcechYTtHPELh"addresses: (....)
3
I'm fairly certain that findOne is not async and your first example should be fine. I'm assuming that your doing this on the client, you want to be sure that the user you're looking for is in your client side collection. In your browser console run Meteor.users.findOne({username: "john"}) and that should take sync out of the question. - Shaded
findOne is supposed to synchronous and reactive. Are you saying that sometimes it returns undefined even when the query should return a value? Note, I generally only use findOne with an _id so that may be part of the reason why I experience different behavior. - Larry Maccherone
@LarryMaccherone Yes, that's it. It returns undefined where it should return something else. And i've noticed with console.log that my data in the routes.js is returned 4 times: 2 times with undefined and 2 times with the object I expect. But in the view, the object is undefined. - Sw0ut
With your edit, it sounds like something crazy is going on. I'm thinking something is not wired up like you think it is. Maybe a scoping issue? Good luck and let us know when you figure it out or if you can post more code for us to help. - Larry Maccherone
I put an image and some code to make you understand. :) - Sw0ut

3 Answers

4
votes

findOne(yourId) is a sync method which is equivalent to find({ _id: yourId}, callback). The difference is that find() allows you to define a callback. If you don't pass a callback to find() this method will be sync.

check wrapAsync: http://docs.meteor.com/#/full/meteor_wrapasync It allows you to code in a sync style with a async operations.

Free lesson on EventedMind: https://www.eventedmind.com/feed/meteor-meteor-wrapasync

0
votes

My experience thus far is that the Meteor Mongodb package is that the functions do not generally provide callbacks (for some reason insert does...), the functions are atomic (thus sync).

There are meteor packages that can make Mongodb async if you want (I havn't tried any).

I guess this sync approach is in line with the simple maintenance goal of Mongodb. Thinking about it, one of my pet peeves using Node is working with async callback waterfalls/nests, they are a pain to create and maintain... and hopefully this will make my code easier to read and understand and change...

0
votes
var future = new Future();

var _h = Hunts.findOne({huntId});

if(_h) {
       future.return(_h)
    } else {
        return future.wait();
    }

on server/startup.js you need: Future = Npm.require('fibers/future');