[solved] Collection find gives undefined. Unable to access fields from a collections

The tracker involved, 'trackerCtrl.liveLoc', what is that one doing?
And this: {{$ctrl.liveLat.lat}}
Apparently he has the data there, but what has put it there and why? Guess it is an Angular thing, but…

This is all starting to make sense now. And it’s my fault - at least the way I’ve structured my code is. I noticed after I tried to parameterise my google api key (for the http request), that google was sending me back a 403 (forbidden). Then if I do some activity in the browser (meteor app) then the 403 goes away. Which means that the apikey variable had then been initialised (but wasn’t at first.
This doesn’t explain (to me) all of that stuff about console.log ‘un-persistence(?)’ but at least I now know 2 things.

  1. The object IS undefined at the point at which I try to do jsonLoc.lat which is why it fails. Can’t help feeling a bit misled though. But at least I’m not going mad.
  2. I’ve got my code in the wrong place. Which brings me all the way back to hunting out the right documentation for my stack and knowledge level. (I thought Angular was the way to go and that Blaze was in the departure lounge?)

@robfallows I did try to string manipulate and var str=JSON.stringify(curLoc); appeared to work but then var str2=str.substring(37,39); failed undefined.

And thx @ralof , I just saw your post , hope this answers your question.
Eating humble pie here.

I think you would ne much more comfortable with Blaze, or even React. Angular is quite hard core :slight_smile:

1 Like

@ ralof Ouch! Yet at the same time , undeniably true !! :grin:

Hi Babysparrow,

Sorry I am french with poor english and I read your question today.

You have alway not find your problem ?

Else : FindOne is json type

But with meteorObservable, Find is Observable array type

And with fetch, promise type.

Also :

var json= await Locs.find({latest: "1"} , {fields: {lat:1}}).fetch();

Can run ?

Hi @tibs245 Your English is better than my French!
The problem I was having is not the datatype but the fact that it was only an object reference and so was unable to access any data within the object. I was thrown a bit by the console log but ultimately I was trying to access data that wasn’t there yet. Haven’t got round to fixing it permanently yet but have a feeling that I’m going to be dealing with callbacks/fibres/futures/promises etc when I do.

Thank babysparrow,
Ok, if you want use this example code for not use callback and quick fix you’re problem with async function.

        myLocsIdInsered = await Locs.insert({
            some: "data"
        }).toPromise();

        myOtherFunction(myLocsIdInsered);

I do not know if this advice will help you, but I hope. :slight_smile: Else I think you know how resolve your problem with callback ^^’

    Locs.insert({
            some: "data"
        }).subscribe((myLocsIdInsered) => {
               othersFunction(myLocsIdInsered);
        });

But if you want return value, I advice “async/await”.

If you need more information, not hesitate but I need more informations on the process

In Meteor, it’s not necessary to use Promises or async/await on MongoDB queries. Meteor already provides Fiber-wrapped replacements for most functions.

So, on the server (and client), you can just do:

// use Meteor's minimongo insert...
const newId = myCollection.insert(someDocument);
console.log(newId);

In fact, if you want to use Promises and async/await, you will need to reference the underlying MongoDB library with:

// use the underlying MongoDB library ONLY ON THE SERVER...
const newId = await myCollection.rawCollection().insert(someDocument);
console.log(newId);

Thx @robfallows , the code (client) is currently this :

            liveLoc(){
                var curLoc = Locs.findOne({latest: "1", target:this.Gtarget} , {fields: {lat:1,lon:1,date:1}});
                var str=JSON.stringify(curLoc);
                console.log(this.Gtarget);
                console.log(curLoc);
                //console.log(curLoc.lat);   ***
                console.log(str);
                //var str2=str.substring(37,39);
                return curLoc;
            }

The commented out code breaks the app.
The commented out code marked by ‘***’ is what I need some way to “wait” for so that the js object is available before I try to access the 'lat' field. As per your previous [excellent] replies, I think that findOne() returns an object not a pointer/reference. So I believe it’s a reactive thing. At the same time I presume that if I were to be successful in accessing 'lat' on the client then I must in some way be blocking the ‘reactiveness(?)’ of the stack.
Not done so yet but I plan to move the code to the server and do the computation there pushing the new fields into the object thus leaving the client to be as reactive as it likes (a sane design principle at least?). I note that simply returning a value - say ‘77’ - or whatever from the server still gets the same problem in the client (i.e. not there yet).
[edit] I’m aware that 'this.' context is different in js than in java. I promise I am ‘looking into it’. :slight_smile:

So, as I understand it, you need to access the full object within the helper. At the moment, you know the helper works, because {{$ctrl.liveLoc.lat}} works. However, in reality, your template display works only because it does one of two things:

Either it waits for the data to become available before rendering, or it renders undefined and then re-renders an actual value when it becomes available.

In Blaze, the helper itself is reactive. Assuming the same in angular, the helper code will run once at start-up (most likely, no data will be available) and then will re-run when data appears (or otherwise changes).

Given that you want to retain the behaviour of the helper for rendering, all you may need to do is ensure you “hook into” the reactive re-run only when data’s there. In which case, this may suffice:

liveLoc() {
  var curLoc = Locs.findOne({ latest: "1", target: this.Gtarget }, { fields: { lat: 1, lon: 1, date: 1 } });
  if (curLoc) {
    var str = JSON.stringify(curLoc);
    console.log(this.Gtarget);
    console.log(curLoc);
    console.log(curLoc.lat);
    console.log(str);
  }
  return curLoc;
}

Caveat: I’ve never used angular, so you may need a different approach. Let me know!

1 Like

Thanks again @robfallows I’ll give that a go.
Everything you have said there matches my understanding. I wish I’d stuck with blaze - it’s just that the meteor tutorial itself seems to ‘push’ angular and react. At least that was my interpretation a few weeks ago.
Looking back over the comments from a few days ago… your comments :

@robfallows ...but I’d still expect a log showing

undefined
undefined
some object
some property

… are correct. Well they are at the moment, but I was trying so many things at that time that I may have missed that. So yes, it “runs then refreshes”.

1 Like

@robfallows : thank-you. That works!
Need to remember what I wanted it for now… :slight_smile:

2 Likes

:joy:

Can anyone on this forum let me know if I need to mark this thread as solved/closed? Since I can’t find an option to do so.

It’s generally not required, but I’ve gone and edited the thread title anyway :slight_smile:

I’ve been training a former java developer to work with Meteor and unexpected behaviour like your example here is driving him nuts (along with general JS async / sync code and functions as values). So at least you’re not alone in this head-scratching exercise haha