[SOLVED] - Why is data not being returned from my mongodb?

Hi all.

This should be a really simple issue to fix. I have one record in my mongodb and I just want to return it and display the location of the lat and long on the google map. If I hard code the data I can get it to work so the issue seems to be with returning the data from the DB. Can anyone see what I’m doing wrong?

Also what are good ways to debug Meteor, I’m finding if I try using console.log() nothing is output anywhere.

Here’s my code, if there’s a better way to share it please let me know. Would be awesome if Meteor worked with stackblitz:

//ui/Map.jsx
const { locations, isLoading } = useTracker(() => {

 const handler = Meteor.subscribe('locations');

  if (!handler.ready()) {
    return { isLoading: true };
  }

  const locations = LocationsCollection.find().fetch();
  if(!locations)
  {
    throw new Meteor.Error('no locations to show');
  }

  return { locations };
});




//db/Locations/Collection.js
import { Mongo } from 'meteor/mongo';

export const LocationsCollection = new Mongo.Collection('locations');



//api/LocationsPublications.js
import { Meteor } from 'meteor/meteor';


import { LocationsCollection } from '/imports/db/LocationsCollection';

Meteor.publish('locations', function publishLocations() {

return LocationsCollection.find();

});




//api/locationsMethods.js
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { LocationsCollection } from '../db/LocationsCollection';
 
Meteor.methods({
  'locations.insert'(location) {
    check(location.lat, String);
    check(location.long, String);

    LocationsCollection.insert({
      lat: location.lat,
      long: location.long,
      createdAt: new Date
    })
  },

  'locations.remove'(locationId) {
    check(locationId, String);
  },

});

The data is actually in fact returning its when I try to use it the problem arises.

If I set the hard coded locations2 data when outputting the markers it works and I can log the data coming back from mongo. When I try to set the data that comes back from mongo which is stored in locations I get an error. Looks like its trying to output the data before its returned from mongo. Any idea how to resolve this?

import React, { useState, Fragment } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { LocationsCollection } from '/imports/db/LocationsCollection';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"

export const Map = () => {

    let locations2 = [ // Just an example this should probably be in your state or props. 
    {
        _id: 1,
      name: "marker1",
      lat: 49.17655,
      long: -123.138564,
      position: { lat: 49.17655, long: -123.138564 }
    },
    {
        _id: 2,
      name: "marker2",
      lat: 49.16659,
      long: -123.113569,
      position: { lat: 49.16659, long: -123.113569 }
    },
    {
        _id: 3,
      name: "marker3",
      lat: 49.15659,
      long: -123.143569,
      position: { lat: 49.15659, long: -123.143569 }
    }
    
  ];
 

    const { locations, isLoading } = useTracker(() => {
     // const noDataAvailable = { tasks: [] };
  
      const handler = Meteor.subscribe('locations');
      console.log(handler);
  
      if (!handler.ready()) {
        return { isLoading: true };
      }
  
      const locations = LocationsCollection.find().fetch();
      console.log(locations);
      if(!locations)
      {
        throw new Meteor.Error('no locations to show');
      }

      return { locations };
    });

  

  const MyMapComponent = withScriptjs(withGoogleMap((props) =>
    <GoogleMap
        defaultZoom={8}
        defaultCenter={{ lat: 55.95192783854873, lng: -3.292913877563525 }}
    >
        
        {locations.map((marker, index) => (
            obj={},
            obj.lat = marker.lat,
            obj.lng = marker.long,
            marker.position=obj,

            <Marker key={marker._id}
                position={marker.position}
            />
        ))}

    </GoogleMap>
   ));

  return (
    <div>
        <MyMapComponent
        isMarkerShown={true}
        googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
        loadingElement={<div style={{ height: `100%` }} />}
        containerElement={<div style={{ height: `400px` }} />}
        mapElement={<div style={{ height: `100%` }} />}
        />
    </div>
  );
};





Figured it out. Had to use Tracker, added this and cast the long/lat values to a number and it worked:

      Tracker.autorun(() => {
        const handler = Meteor.subscribe('locations');
        const isReady = handler.ready();
        console.log(`Handle is ${isReady ? 'ready' : 'not ready'}`);
        if(!isReady)
        {
          return { isLoading: true };
        }
       
      });

I would say that you are using a String instead of a Number on the params, and also, it seems that you are not waiting for the server to send the results to the front end, because it should work with useTracker hook - it uses Tracker.autorun under the hood (react-packages/useTracker.ts at master · meteor/react-packages · GitHub)

I would check like this to verify if the data is loading.

if (isLoading) return 'Loading...'

And then proceed with the rest of the code.

I’ve removed the Tracker.autorun code and it still works, is this what you meant? Anything else I can improve on?

This is my map code:

import React, { useState, Fragment } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { LocationsCollection } from '/imports/db/LocationsCollection';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"

export const Map = (props) => {

    const { locations, isLoading } = useTracker(() => {

        const handler = Meteor.subscribe('locations');
        const isReady = handler.ready();
        //console.log(`Handle is ${isReady ? 'ready' : 'not ready'}`);
        if(!isReady)
        {
          return { isLoading: true };
        }
       
  
      const locations = LocationsCollection.find().fetch();
    
      return { locations };
    });

  

  const MyMapComponent = withScriptjs(withGoogleMap((props) =>
    <GoogleMap
        defaultZoom={+props.defaultZoom}
        defaultCenter={{ lat: +props.defaultCenterLat, lng: +props.defaultCenterLng }}
    >
        
        {locations.map((marker, index) => (
            obj={},
            obj.lat = +marker.lat,
            obj.lng = +marker.long,
            marker.position=obj,

            <Marker key={marker._id}
                position={marker.position}
            />
        ))}

    </GoogleMap>
   ));

  return (
    <div>
       {isLoading && <div className="loading">loading...</div>}
        <MyMapComponent
        defaultZoom={props.defaultZoom}
        defaultCenterLat={props.defaultCenterLat}
        defaultCenterLng={props.defaultCenterLng}
        isMarkerShown={true}
        googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
        loadingElement={<div style={{ height: `100%` }} />}
        containerElement={<div style={{ height: `400px` }} />}
        mapElement={<div style={{ height: `100%` }} />}
        />
    </div>
  );
};





I would do something like this

export const Map = (props) => {

    const { locations, isLoading } = useTracker(() => {

        const handler = Meteor.subscribe('locations');
        const isReady = handler.ready();
        //console.log(`Handle is ${isReady ? 'ready' : 'not ready'}`);
        if(!isReady)
        {
          return { isLoading: true };
        }
       
  
      const locations = LocationsCollection.find().fetch();
    
      return { locations };
    });

  

  const MyMapComponent = withScriptjs(withGoogleMap((props) =>
    <GoogleMap
        defaultZoom={+props.defaultZoom}
        defaultCenter={{ lat: +props.defaultCenterLat, lng: +props.defaultCenterLng }}
    >
        
        {locations.map((marker, index) => (
            obj={},
            obj.lat = +marker.lat,
            obj.lng = +marker.long,
            marker.position=obj,

            <Marker key={marker._id}
                position={marker.position}
            />
        ))}

    </GoogleMap>
   ));

if (isLoading) return <div className="loading">loading...</div>

  return (
    <div>
        <MyMapComponent
        defaultZoom={props.defaultZoom}
        defaultCenterLat={props.defaultCenterLat}
        defaultCenterLng={props.defaultCenterLng}
        isMarkerShown={true}
        googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
        loadingElement={<div style={{ height: `100%` }} />}
        containerElement={<div style={{ height: `400px` }} />}
        mapElement={<div style={{ height: `100%` }} />}
        />
    </div>
  );
};
1 Like

Awesome, thank you. I think your way is clearer.

1 Like