Well, I’ve tried practically every combination of find/findOne along with return json; (which returns the json object - so kinda works)
or return json[0]; (this works too)
or return json[0].lat; (which gives undefined error)
fetch() doesn’t work with findOne either for some reason.
Every single thing that I’ve read off the internet/google does not work. All I want is to get the numeric value of the variable ‘lat’.
Are you trying to access this data from the client or the server? This is going to make a big difference because on the client the data may not be available because it hasn’t been sent by a publication, or you could just be running into a race condition where you are trying to display but not waiting for the data to be available first and sometimes it displays because it arrived fast enough, and other times it doesn’t because the data arrived to the client yet.
Hi & thanks , copleyja. It’s running on the client side in a helper function.
liveLat(){
var json= Locs.findOne({latest: "1"} , {fields: {lat:1}});
var str=JSON.stringify(json);
//var ejson = EJSON.parse(str);
//var obj = JSON.parse(str);
console.log(str);
console.log(json);
The annoying thing is that the console will show both the string AND the json object. But there just doesn’t seem to be any way whatsoever to access the field named ‘lat’ by any conventional means. Both the JSON and EJSON parsers fail with “unexpected data”.
I take you point about race condition but feel that if the console log shows the data I expect then why can I not access it using one of the [many] methods such asx=json.lat or json.lat.value or json["lat"] or json["lat"].value … or whatever. It’s driving me 7 hours of nuts now!!
Accept that I am fairly new to meteor (usually java/c++/android,me) but either I have so utterly missed something or meteor is just the most counter intuitive thing I’ve ever encountered. I do obviously realise it must be me though.
I’m afraid it doesn’t (and I really have tried everything!). I’m taking the data out in the html at the moment by doing this {{$ctrl.liveLat.lat}}
which is the only way I can get it working. But trouble is I need to do a serious amount of computation in the js on the latitude and longitude fields (convert to UK osgrid refs) and so I need to access them there.
It’s something I’m doing wrong but cannot see due to my lack of Meteor experience but as purely a sidenote here I solemnly promise I spent 8 hours trying to research just this alone and got nowhere : answers like yours came around and I tried them only to get ‘undefined’.
Research an issue like this for c++, java, unix, android and you’ll get something between 1-15 minutes… but this!?!?! Meteor/angular/mongo/node.js/javascript/json/ejson seem incredibly difficult to gain decent/incisive documentation or online help for [presumably because there’s so many different things in the ‘field of play’ and with so many different versions of them all too] without resorting to a direct question on a forum like this. Soorry for that.
@babysparrow maybe I get it wrong. You’re getting errors on the parsers, right? If so, why are you using parsers? You already have an object ‘json’, where you can access ‘lat’ and ‘lon’ directly:
var json = Locs.findOne({latest: "1"} , {fields: {lat:1, lon:1}});
var lat = json.lat;
var lon = json.lon;
@bordalix my bad on the confusion there. I was merely attempting to stringify then reparse (json) the data just to see what happened. The stringify worked, but the JSON.parse always gives an error. I felt for a couple of hours that this was my biggest clue … it probably still is. [sidenote: I don’t want to end up with loads of logic in the html if can be avoided … not exactly MVC, IMHO , AFAIK ; starting to remind me of the early bad old days of html/java/jsp … yes I’m old… started with COBOL, me].
This code :
liveLoc(){
jsonLoc = Locs.findOne({latest: "1", target:this.Gtarget} , {fields: {lat:1,lon:1,date:1}});
console.log(this.Gmode);
console.log(this.Gtarget);
console.log(jsonLoc);
var testlat=jsonLoc.lat; This is line 64 in tracker.js**
console.log(testlat);
return jsonLoc;
}
gives this error :
modules.js?hash=1ab1f541404583097e9129ea3e137c42a9e333d8:15833 TypeError: Cannot read property 'lat' of undefined
at trackerCtrl.liveLoc (tracker.js:64)
Yes it’s observed (it has to be)… does that make a difference?
Second point. I’m aware that depending on what did the insert to the mongo collection then _id may be a string or it may be an object and wonder if this is causing the json parser to fail. My id’s are all objects rather than strings. I cannot exclude the _id because the observer gives an error.
Additionally. Am not using publish/subscribe. Am still on autopublish (or whatever that is called) and this app will probably stay that way. A few months ago I did the meteor/blaze todo app which takes autopublish out etc, etc. Then I did the same again with angular. But I don’t need to do that so far for this app - probably never will. If that makes a difference (and I don’t see why it should) then feel free to dress me down.
I have a feeling that this is running before the published data is ready. Thanks to the reactivity, it will re-run correctly when the data is available.
All you should need to do is check if the document is undefined by nesting it inside an #if:
I thought I should join in this conversation. It may be helpful to recap a few things first:
collection.find() returns a cursor. You can’t access documents or document properties directly from a cursor. You need to use an appropriate cursor method (e.g. .fetch(), .map() or forEach()).
From (1), find().fetch() returns an array of documents, as others have already pointed out.
collection.findOne() is exactly equivalent to collection.find().fetch()[0]. It returns the first matching document from the cursor identified by collection.find().
Returned documents are not JSON-encoded - they are JavaScript objects. In other words, JSON.parse will not work.
There is little point using the fields modifier if you are using autopublish, since that publishes all fields by default and it’s only really useful in a publication to minimise network use.
If the document is available on the client (and it may not be), then I would expect a query of the form const lat = Locs.findOne(selector).lat; to work as expected. Equally, const lat = Locs.find(selector).fetch()[0].lat; should work for reason (2).
If the document is not available on the client when you expect it, then @coagmano’s answer above will ensure that it reactively updates for presentation when it does arrive. There are other ways of achieving that, but that’s a really easy thing to test.
Failing that, I’d be interested in double-checking what’s actually in the database. To do that, start your application and in another terminal in the same application root, do meteor mongo. You will then have a MongoDB command window. In that, do db.locs.findOne({latest: "1"}) and paste the result here. (I’ve assumed locs is the name of your collection - if not, use the correct name).
And I access lat and lon in the html (templated) using this : {{$ctrl.liveLoc.lat}}
There’s never been an issue with that. It works.
So to draw a line under some of the other/older posts … that’s the code and it works (I’m also using findOne and I’m aware of cursor with find() without .fetch() .
Yes, the collection is called locs and I’m currently using meteor/mongo on :3001 and here is the row/document which it does retrieve :
So far … all good.
It’s just that I cannot seem to access the fields lat or lon within the helper function. Maybe I shouldn’t be trying to in the first place? I was just wandering along writing code (in not my most familiar language) when I tried to do this : return jsonLoc.lat … and 2 days later I’m feeling really guilty that I’m wasting peoples time on something that is certainly my own fault. But I just don’t understand why.