A React Native + MongoDB Realm example application for allowing users to see location and movement of their own devices or those of people in the same group.
This React Native app requires a MongoDB Realm backend that can be found here.
To get a better overview of the implementation as well as the RealmDB data modeling, partitions, and permissions, see Diagrams.
Screen.Recording.2021-08-20.at.16.17.42.mov
In order to use React Native and iOS and/or Android simulators, please refer to the React Native environment set-up docs and view instructions for React Native CLI Quickstart.
# using https
git clone https://github.com/realm/FindOurDevices
# using ssh
git clone git@github.com:realm/FindOurDevices.git
cd FindOurDevices
npm install
npx pod-install
If you have set up your Realm backend (see FindOurDevices-backend) you can copy the Realm App ID from the MongoDB Realm UI.
Once copied, open /app/config.js
and paste the ID as the value of REALM_APP_ID
.
- Start Metro (the JavaScript bundler). Open a terminal and from the root of the project run:
npx react-native start
- Build the app and run it on a simulator. Open a separate terminal and from the root of the project run:
# open iOS simulator
npx react-native run-ios
# open android emulator
npx react-native run-android
The app is implemented to only be notified of a location change if the device moves a minimum number of meters. You may change the minimum number in /app/hooks/useLocation.js
and replace the value of the constant METERS_BEFORE_UPDATING_LOCATION
.
The first time you boot the app on a specific iOS device and log in, the app will request permission to use your location. Make sure you allow location sharing since iOS users only have one chance to respond to that alert.
Simulate movement on a simulator:
- Run the app
- From the menu bar, select
Features > Location
- Set custom coordinates or choose to simulate riding a bike, a car, or running, etc.
- When done simulating movement, remember to set
Features > Location
back toNone
to prevent unnecessary updates.
⚠️ The first time a user adds a simulator device to their account, the device's location will not be set because theMenu Bar > Features > Location
will be set toNone
. The device will therefore not show up on the map screen. To set a location for the device, simply follow the steps above.
The first time you boot the app on a specific Android device and log in, the app may request permission to use your location. Make sure you allow location sharing.
Simulate movement on an emulator:
- Run the app
- From the emulator toolbar, select the
...
icon - Select the
Location
menu item - Set a custom address or press the
routes
tab to enter a start and end address and pressPLAY ROUTE
The current app does not support location updates while the app is minimized. The app must be running in the foreground for location change notifications to be emitted.
If you are developing for Android and want to use Google Maps for the map functionality, you need to get an API key and set up a billing account with Google.
To circumvent this, we have chosen to use the library react-native-maps-osmdroid
which is a wrapper around react-native-maps
that lets us use OpenStreetMaps instead of Google Maps. (The library API is mostly the same, thus the usage is the same.)
-
Install the dependency
npm install react-native-maps # If using iOS, also run: npx pod-install
-
In
/app/components/Map.js
, replace...import MapView from 'react-native-maps-osmdroid';
import MapView from 'react-native-maps';
-
Refer to the react-native-maps docs and Google Maps API docs for instructions on how to proceed.
- The UI is less modern
- The callout shown when pressing a marker/pin remains in the same place on the screen even when dragging the map or following a moving marker.
- All pins use the same colors
- When there is only one device or member on the map and you choose to view "All" markers, the map region is too zoomed in.
However, OpenStreetMap provides mapping that does not depend on Google's backend, and thus does not require a billing account or payment and does not provide Google with tracking information.
A great help when troubleshooting is to look at the log of the app in the MongoDB Realm UI under Manage > Logs
in the sidebar.
When developing and modifying schemas or making changes to documents directly in MongoDB Atlas, you may experience issues syncing the modfied object if the changes do not conform to your Realm data model. Realm Sync only propagates valid objects without throwing any errors if any of the objects do not conform to your schema/model.
Make sure to check that all expected fields and types exist on the object/document.
Some issues may also be related to permissions (see Permission errors).
The first time you import your backend Realm app to MongoDB Realm, some triggers may not get enabled. Go to the MongoDB Realm UI then navigate to Build > Triggers
in the sidebar. Enable any trigger that is not currently enabled.
Also make sure the trigger is configured correctly on the backend. Trigger configurations contain a match
field where you may specify when the trigger should fire using the MongoDB query language.
When developing, if you notice from looking at the logs in the MongoDB Realm UI that a trigger is fired but the function that the trigger is supposed to call is not called, you may be using a device with an IP-address that is not listed on the access list of the API key (see Permission errors).
When the Realm backend was set up, you had to add your IP to the Realm CLI API key access list. If you are developing from another device or using a different network connection (or other reasons), your IP address will be different.
To edit the access list, navigate to Access Mananger > Project Access > API Keys
at the top of the MongoDB Atlas UI and choose which of your keys to edit.
There is a known issue with network change notifications on the iOS simulator that occurs when the simulator is (a) running, then (b) WiFi is turned off, then (c) WiFi is turned on again. The simulator will be notified when the WiFi got turned off, but not when it got reenabled.
To be able to test this scenario with greater confidence, please use a real device.
The diagrams presented and the notes therein provide insights into ways of thinking about RealmDB data modeling, partitioning, and permissions.
FindOurDevices uses a synced cluster with only synced realms. Data access rules and permissions are different for non-synced realms which provide document-level and field-level rules.
A visual overview of what a user can do with the application.
Application capabilities.
An Entity Relationship diagram of the FindOurDevices data model showing all Realm objects and their relationships.
Data modeling in Realm.
Potential problems that you may run into when modeling data and referencing objects, as well as various solutions for circumventing the issue and what solution FindOurDevices uses.
Partitioning in Realm.
A comparison of the permissions of two different applications (one being FindOurDevices) for the part of the app that uses a shared realm. It explains why the sync permission rules for FindOurDevices are not the same (i.e. does not allow “write” permission).
Partitions and permissions for synced realms.
Explanation of permission related issues of an earlier data model version of FindOurDevices and how a remodel solved the issue.
Partitions and permissions for synced realms and how to spot a similar weakness in your data model.
Illustration of how Realm is integrated in FindOurDevices (for the use case of having groups) and from what exact places of the data model the data on various screens come from. It also shows what Realm-related operations are performed when the user interacts with the screen.
Realm integration, denormalization, and opening/closing of realms.
Illustration of what activities happen and how the data flows when the main use case of the app occurs (i.e. a device moves X meters and the new location can be seen on the map by the user and any group members that the user is a part of). All activities within a specific column in the diagram represent what happens on that specific entity (e.g. on John’s phone, Mary’s phone, or on the MongoDB Realm backend).
Realm integration, Realm Sync, partitioning, and change listeners.