Mobile Bytes #10: BookKeeper App with Embedded Objects

G’Day, Folks, :wave:

Hope you all are enjoying Realm rides :smiley: . Apologies for the long wait, but here I am with our 10th byte.

I talked about Embedded Objects a while ago, this week I created an app to show how embedded objects get synced to Atlas and how schema on cloud looks like.

The app will also show the difference when using Embedded Objects v/s 1-to-many and inverse relationships that were discussed in BookLog Application.

The steps for creating the Book Keeper App are similar to BookLog Application linked above

Brief Pointers

  1. Create an Atlas Free Tier Cluster.
  2. Create Realm App in the same location as your cluster.
  3. Enable Syncing with partition-based sync and assign read/write permissions to the user partition.
  4. Turn Development Mode On.

Author and Book Realm Schema Model

@RealmClass(embedded=true)
open class Author(

    @Required
    var name: String = "",

    var country: String = "",

    var email: String = ""

): RealmObject() {}

open class Book(
    @PrimaryKey
    var _id: ObjectId = ObjectId(),

    @Required
    var name: String = "",

    var isRead: Boolean = false,

    var _partition: String = "",

    var authors: RealmList<Author> = RealmList()
): RealmObject() {}

As discussed in the Embedded Objects topic, the Author class is embedded in the Book class instead of being a separate class with its own primary key. Embedded Objects fit MongoDB Document Model much better compared to 1-to-Many and inverse relationships.

Performing Writes on the Embedded Objects

 val authorOne = Author("Hector Garcia", "Spain", "hectorgarcia@gmail.com")
 val authorTwo = Author("Francesc Miralles", "Spain", "francescmiralles@gmail.com")

val book = Book(name = "Ikigai", isRead = false, _partition = user!!.id)
   book.authors.add(authorOne)
   book.authors.add(authorTwo)

 val authorThree = Author("J.K Rowling", "United Kingdom", "jkrowling@gmail.com")
 val bookTwo = Book(name ="Harry Potter and the Chamber of secrets", isRead = false, _partition = user!!.id)

 bookTwo.authors.add(authorThree)

Commit Changes to Realm

 realmClass.executeTransactionAsync({ realm ->
                realm.insert(book)
                realm.insert(bookTwo)
            }

Reads and Displaying Result

I implemented Recycler View to display author and book details. It had a simple read query.

BookListAdapter(realmList.where(Book::class.java).sort("name").findAll())

The results are displayed as shown below:

image

Schema on Cloud

The schema on syncing to Atlas looks like the below. There is one Book Collection that is created instead of two that were created previously with Realm Relationships.

{
  "title": "Book",
  "bsonType": "object",
  "required": [
    "_id",
    "_partition",
    "name",
    "isRead"
  ],
  "properties": {
    "_id": {
      "bsonType": "objectId"
    },
    "_partition": {
      "bsonType": "string"
    },
    "name": {
      "bsonType": "string"
    },
    "isRead": {
      "bsonType": "bool"
    },
    "authors": {
      "bsonType": "array",
      "items": {
        "title": "Author",
        "bsonType": "object",
        "required": [
          "name",
          "country",
          "email"
        ],
        "properties": {
          "name": {
            "bsonType": "string"
          },
          "country": {
            "bsonType": "string"
          },
          "email": {
            "bsonType": "string"
          }
        }
      }
    }
  }
}

To make it easier, I have added dummy data and subtracted UI complications of adding Book and Author details.

I hope the provided information is useful. I would love to know your approach to defining schemas for your Realm Applications.

Cheers. :performing_arts:

3 Likes