MongoDB Realm Mobile App Functions

I am new to MongoDB Realm and am trying to understand the ‘correct’ approach to call and execute functions. For example, I want to create a very simple application (that can scale) where users can create an account and create an event.

Prior to Realm, I was using Node JS and created a function that would interact with my Atlas database by updating the User, Event, and OutlierEvents collections. The outlier collection is used in the instance where a user has over 100 events in the future (events 101+). The examples below are just snapshots into each collection. My question is focused on calling functions in Realm.

User Collection

_id: ObjectID
name: string
events: array of event ObjectIDs that have not occurred (up to 100 ids)
countCurrentEvents: number
hasOutlierEvents: boolean

Event Collection

_id: ObjectID
eventCreator: ObjectID (id will match the user's id)
name: string
description: string
eventDate: date

OutlierEvents Collection

_id: ObjectID (id will match a user's id)
events: array of event ObjectIDs that have not occurred (101+ ids)

Based on the example above, a user can create an event. All events in the future will be stored in the user’s events array, but if the user has more than 100 events in the future scheduled, a new outlier document is created for this user (id matches the user’s id) and the additional events are stored in the outlier collection. As events expire these outlier events will be moved to the main events array in the user’s document.

I previously had a function ‘createEvent’ working in Atlas through Node JS. In order to transition to Realm, I created a new function called ‘createEvent’. I then went into my mobile application (built on React Native) and created a button the executes the following:

const createEvent = async () => {
  try {
    await user.functions.createEvent()
  catch (error) {
    Alert.alert('error')
  }
}

When I click this button, an event is created. If the number of current events exceeds 100, then events will be saved to the OutlierEvents collection. The ‘createEvent’ function looks something like this (not perfect but for demonstration purposes I hope will suffice):

exports = async function(payload, response) {
  const userId = "61250a623a67bb23f55c1c11"
  const users = context.services.get("mongodb-atlas").db("myDB").collection("users")
  const events = context.services.get("mongodb-atlas").db("myDB").collection("events")
  const currentUser = await users.findOne({ "_id": BSON.ObjectId(userId)

  if(currentUser) {
    const event = {
      eventCreator: currentUser._id,
      name: "New Event",
      description: "Tell others about your event!",
      eventDate: new Date()
    }
    const newEvent = await events.insertOne(event)

    await users.updateOne(
      { "_id": BSON.ObjectId(userId)},
      { $push: {
        events: {
          _id: newEvent.insertedId
        }
      },
        $inc: { countCurrentEvents: 1 }
      }
    )
    
    if(currentUser.hasOutlierEvents) {
    ...
    }
  }
}

At a high-level, is this the right approach? It works exactly how I intended but I am worried I am not getting the benefits of Realm (offline first, sync, etc.). I ask because several tutorials may use a function like:

const createEvent = (newEvent) => {
  const projectRealm = realmRef.current
  projectRealm(() => {
    projectRealm.create(
      "Event",
      new Event({
        eventCreator: currentUser._id,
        name: "New Event",
        description: "Tell others about your event!",
        eventDate: new Date()
    )
    ... (I am not sure how I would execute the remainder of this function)
  }
}

I think where I am getting lost is when I am trying to build more complex functions (e.g. interacting among multiple collections). Almost all of the tutorials / examples I can find online are for simple ToDo style apps.

Is it possible to 1) confirm my approach will work or 2) expand on how to make it work with Realm with code, if possible. I am really excited to use Realm but am struggling to find great resources so any help here would be immensely appreciated. Cheers!

Hello @Jason_Tulloch

My name is Josman and I am happy to help you with this query.

My suggestion is that normally a server function will be useful if you have a use case that might need to interact with several collections. An example of this could be an addNewFriendRequest. In this imaginary call Function, every time a user adds another user as a friend, you might need to perform several operations that you wouldn’t want to be performed on the client. These operations might be access to the recipient user data, see if the user has some permissions, etc.

In your scenario, I am not seeing this potential use case. Please, correct me if I am wrong. Therefore, you might use Realm Sync to accomplish this. In this sense, you will benefit from the offline-first approach that you would not be having when using a call Realm Function.

Here are two nice articles about using different partition strategies that might help you accomplish your use case by using Realm Sync:

  1. Realm Partitioning Strategy: This article will help you pick the right partitioning for your app by exploring different strategies to choose the right one.
  2. Realm Data and Partitioning Strategy Behind the WildAid O-FISH Mobile Apps: This is an article that will show you the partition strategy used in a realm-world app called O-FISH Realm, a multi-platform application that enables officers to browse and record boarding report data from their mobile devices to protect vulnerable marine environments.

Please let me know if you have any additional questions or concerns regarding the details above.

Kind Regards,
Josman

Josman, thank you for taking the time to reply, it is much appreciated and I think I am starting to get my bearings.

Your example makes sense, if there was a new friend request two separate user documents would need to be accessed through the server, which is why an offline-first approach would not work (please correct me if I am wrong there). In this specific example you provided, executing a server side function is the correct approach then, similar to the general setup I had above to create an event? Specifically, the user may click a new friend request button that would need to save the request to the current user’s document as well as the new friend’s document.

In my example above, I was under the impression that I could be interacting with a maximum of 3 collections (Users, Events, and OutlierEvents). Based on your response, am I correct that Realm Sync would accomplish this as these collections can be saved to the Realm App if the user creating the event was offline? Then when the user is connected to the server an event would be created and saved to the atlas database?

I understand how to create a new event and save it to my Events collection. How would I update the Users events array and if the events array has 100 current events, push the furthest out event to the OutlierEvents collection? In this scenario would I only create the new event and then have a trigger for when it is created on the server to finish the remaining logic?

Thanks so much for the help!

Hello @Jason_Tulloch

Your example makes sense, if there was a new friend request two separate user documents would need to be accessed through the server, which is why an offline-first approach would not work (please correct me if I am wrong there). In this specific example you provided, executing a server side function is the correct approach then, similar to the general setup I had above to create an event? Specifically, the user may click a new friend request button that would need to save the request to the current user’s document as well as the new friend’s document.

Yes, to me if I need to access information that won’t be in the local database or I don’t need it to be in Sync, then a call Realm Function makes totally sense. In the above scenario, when a user clicks on addFriend, we might need to access the recipient user data to know something before adding that friend to the list of friends. Here you might need to read data that has a different level of access and therefore you want to have that business logic in a cloud function.

In my example above, I was under the impression that I could be interacting with a maximum of 3 collections (Users, Events, and OutlierEvents). Based on your response, am I correct that Realm Sync would accomplish this as these collections can be saved to the Realm App if the user creating the event was offline? Then when the user is connected to the server an event would be created and saved to the atlas database?

Yes, exactly. In your scenario, if you only need to access your user data, i.e. the user that is currently logged into your application and the events that are linked to this user (Events and OutlierEvents) then it would make sense to have all this data in Sync. Therefore:

  1. You will be able to create new events even when offline. These will be synchronized when connectivity is restored.
  2. You will have access to all this information on multiple devices. That is, when the user connects to another device, the latest updated information will be displayed.

I understand how to create a new event and save it to my Events collection. How would I update the Users events array and if the events array has 100 current events, push the furthest out event to the OutlierEvents collection? In this scenario would I only create the new event and then have a trigger for when it is created on the server to finish the remaining logic?

Yes, this would be a good approach. You can have a database trigger that monitors the Events collection for each update or insert and when the events are more than the specified number (in your case 100+) then you could run the necessary logic for your use case.

Please let me know if you have any additional questions or concerns regarding the details above.

Kind Regards,
Josman

Josman, thank you so much for walking me through this, your responses have been very helpful!

1 Like

Hello @Jason_Tulloch

I am glad I was able to help. Please note that if you have any questions or require any additional assistance, please feel free to contact us and we will be happy to help.

Thank you again for choosing MongoDB.

Kind Regards,
Josman