# New Realm Data Types: Dictionaries/Maps, Sets, Mixed, and UUIDs

## TL;DR

Starting with Realm Javascript 10.5, Realm Cocoa 10.8, Realm .NET 10.2,
and Realm Java 10.6, developers will be able persist and query new
language specific data types in the Realm Database. These include
Dictionaries/Maps, Sets, a Mixed type, and UUIDs.

## Introduction

We're excited to announce that the Realm SDK team has shipped four new
data types for the Realm Mobile Database. This work – prioritized in
response to community requests – continues to make using the Realm SDKs
an intuitive, idiomatic experience for developers. It eliminates even
more boilerplate code from your codebase, and brings the data layer
closer to your app's source code.

These new types make it simple to model flexible data in
Realm, and easier to work across Realm and
MongoDB Atlas. Mobile developers
who are building with Realm and MongoDB Realm
Sync can leverage the
flexibility of MongoDB's data structure in their offline-first mobile
applications.

Read on to learn more about each of the four new data types we've
released, and see examples of when and how to use them in your data
modeling:

-   Dictionaries/Maps
-   Mixed
-   Sets
-   UUIDs

> **Build better mobile apps with Atlas Device Sync**: Atlas Device Sync is a fully-managed mobile backend-as-a-service. Leverage out-of-the-box infrastructure, data synchronization capabilities, built-in network handling, and much more to quickly launch enterprise-grade mobile apps. Get started now by build: Deploy Sample for Free!

## Dictionaries/Maps

Dictionaries/maps allow developers to store data in arbitrary key-value
pairs. They're used when a developer wants to add flexibility to data
models that may evolve over time, or handle unstructured data from a
remote endpoint. They also enable a mobile developer to store unique
key-value pairs without needing to check the data for uniqueness before
insertion.

Both Dictionaries and Maps can be useful when working with REST APIs,
where extra data may be returned that's not defined in a mobile app's
schema. Mobile developers who need to future-proof their schema against
rapidly changing feature requirements and future product iterations will
also find it useful to work with these new data types in Realm.

Consider a gaming app that has multiple games within it, and a single
Player class. The developer building the app knows that future releases
will need to enable new functionality, like a view of player statistics
and a leaderboard. But the Player can serve in different roles for each
available game. This makes defining a strict structure for player
statistics difficult.

With Dictionary/Map data types, the developer can place a gameplayStats
field on the Player class as a dictionary. Using this dictionary, it's
simple to display a screen that shows the player's most common roles,
the games they've competed in, and any relevant statistics that the
developer wants to include on the leaderboard. After the leaderboard has
been released and iterated on, the developer can look to migrate their
Dictionary to a more formally structured class as part of a formal
feature.

::::tabs
:::tab]{tabid="Kotlin"}
``` kotlin
import android.util.Log
import io.realm.Realm
import io.realm.RealmDictionary
import io.realm.RealmObject
import io.realm.kotlin.where
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import java.util.AbstractMap

open class Player : RealmObject() {
    var name: String? = null
    var email: String? = null
    var playerHandle: String? = null
    var gameplayStats: RealmDictionary = RealmDictionary()
    var competitionStats: RealmDictionary = RealmDictionary()
}

realm.executeTransactionAsync { r: Realm ->
    val player = Player()
    player.playerHandle = "iDubs"
    // get the RealmDictionary field from the object we just created and add stats
    player.gameplayStats = RealmDictionary(mapOf())
            .apply {
                "mostCommonRole" to "Medic"
                "clan" to "Realmers"
                "favoriteMap" to "Scorpian Bay"
                "tagLine" to "Always be Healin"
                "nemesisHandle" to "snakeCase4Life"
            }
    player.competitionStats = RealmDictionary(mapOf()).apply {
        "EastCoastInvitational" to "2nd Place"
        "TransAtlanticOpen" to "4th Place"
    }
    r.insert(player)
}

// Developer implements a Competitions View -
// emit all entries in the dictionary for view by the user
val player = realm.where().equalTo("name", "iDubs").findFirst()
player?.let {
    player.competitionStats.addChangeListener { map, changes ->
        val insertions = changes.insertions
        for (insertion in insertions) {
            Log.v("EXAMPLE", "Player placed at a new competition $insertion")
        }
    }
}

fun competitionFlow(): Flow = flow {
    for ((competition, place) in player!!.competitionStats) {
        emit("$competition - $place")
    }
}

// Build a RealmQuery that searches the Dictionary type
val query = realm.where().equalTo("name", "iDubs")
val entry = AbstractMap.SimpleEntry("nemesisHandle", "snakeCase4Life")
val playerQuery = query.containsEntry("gameplayStats", entry).findFirst()

// remove player nemesis - they are friends now!
realm.executeTransaction { r: Realm ->
    playerQuery?.gameplayStats?.remove("nemesisHandle")
}
```
:::
:::tab[]{tabid="Swift"}
``` swift
import Foundation
import RealmSwift

class Player: Object {
    @objc dynamic var name: String?
    @objc dynamic var email: String?
    @objc dynamic var playerHandle: String?
    let gameplayStats = Map()
    let competitionStats = Map()
}

let realm = try! Realm()
try! realm.write {
    let player = Player()
    player.name = "iDubs"

    // get the Map field from the object we just created and add stats
    let statsDictionary = player.gameplayStats
    statsDictionary["mostCommonRole"] = "Medic"
    statsDictionary["clan"] = "Realmers"
    statsDictionary["favoriteMap"] = "Scorpian bay"
    statsDictionary["tagLine"] = "Always Be Healin"
    statsDictionary["nemesisHandle"] = "snakeCase4Life"

    let competitionStats = player.competitionStats

    competitionStats["EastCoastInvitational"] = "2nd Place"
    competitionStats["TransAtlanticOpen"] = "4th Place"

    realm.add(player)

    // Developer implements a Competitions View -
    // emit all entries in the dictionary for view by the user

    // query for all Player objects
    let players = realm.objects(Player.self)

    // run the `.filter()` method on all the returned Players to find the competition rankings
    let playerQuery = players.filter("name == 'iDubs'")

    guard let competitionDictionary = playerQuery.first?.competitionStats else {
        return
    }

    for entry in competitionDictionary {
        print("Competition: \(entry.key)")
        print("Place:   \(entry.value)")
    }

    // Set up the listener to watch for new competition rankings
    var notificationToken = competitionDictionary.observe(on: nil) { changes in
        switch changes {
        case .update(_, _, let insertions, _):
            for insertion in insertions {
                let insertedCompetition = competitionDictionary[insertion]
                print("Player placed at a new competition \(insertedCompetition ?? "")")
            }
        default:
            print("Only handling updates")
        }
    }
}
```
:::
:::tab[]{tabid="JavaScript"}
``` javascript
const PlayerSchema = {
  name: "Player",
  properties: {
    name: "string?",
    email: "string?",
    playerHandle: "string?",
    gameplayStats: "string{}",
    competitionStats: "string{}",
  },
};

let player;

realm.write(() => {
  player = realm.create("Player", {
    name: "iDubs",
    gameplayStats: {
      mostCommonRole: "Medic",
      clan: "Realmers",
      favoriteMap: "Scorpian Bay",
      tagLine: "Always Be Healin",
      nemesisHandle: "snakeCase4Life",
    },
    competitionStats: {
      EastCoastInvitational: "2nd Place",
      TransAtlanticOpen: "4th Place",
    }
  });

// query for all Player objects
const players = realm.objects("Player");
// run the `.filtered()` method on all the returned Players to find the competition rankings
const playerQuery = players.filtered("name == 'iDubs'");

// Developer implements a Competitions View -
// emit all entries in the dictionary for the user to view

const competitionDictionary = playerQuery.competitionStats;

if(competitionDictionary != null){
  Object.keys(competitionDictionary).forEach(key => {
            console.log(`"Competition: " ${key}`);
            console.log(`"Place: "  ${p[key]}`);
        }
}

// Set up the listener to watch for new competition rankings
  playerQuery.addListener((changedCompetition, changes) => {
     changes.insertions.forEach((index) => {
       const insertedCompetition = changedCompetition[index];
       console.log(`"Player placed at a new competition " ${changedCompetition.@key}!`);
  });

// Build a RealmQuery that searches the Dictionary type
const playerNemesis = playerQuery.filtered(
  `competitionStats.@keys = "playerNemesis" `
);

// remove player nemesis - they are friends now!
if(playerNemesis != null){
  realm.write(() => {
    playerNemesis.remove(["playerNemesis"]);
  });
}
```
:::
:::tab[]{tabid=".NET"}
``` csharp
public class Player : RealmObject
{
  public string Name { get; set; }
  public string Email { get; set; }
  public string PlayerHandle { get; set; }

  [Required]
  public IDictionary GamePlayStats { get; }

  [Required]
  public IDictionary CompetitionStats { get; }
}

realm.Write(() =>
{
    var player = realm.Add(new Player
    {
        PlayerHandle = "iDubs"
    });

    // get the RealmDictionary field from the object we just created and add stats
    var statsDictionary = player.GamePlayStats;

    statsDictionary["mostCommonRole"] = "Medic";
    statsDictionary["clan"] = "Realmers";
    statsDictionary["favoriteMap"] = "Scorpian Bay";
    statsDictionary["tagLine"] = "Always be Healin";
    statsDictionary["nemesisHandle"] = "snakeCase4Life";

    var competitionStats = player.CompetitionStats;

    competitionStats["EastCoastInvitational"] = "2nd Place";
    competitionStats["TransAtlanticOpen"] = "4th Place";
});

// Developer implements a Competitions View -
// emit all entries in the dictionary for view by the user

var player = realm.All().Single(t => t.Name == "iDubs");

// Loop through one by one
foreach (var competition in player.CompetitionStats)
{
    Debug.WriteLine("Competition: " + $"{competition.Key}");
    Debug.WriteLine("Place: " + $"{competition.Value}");
}

// Set up the listener to emit a new competitions
var token = competitionStats.
    SubscribeForKeyNotifications((dict, changes, error) =>
{
    if (changes == null)
    {
        return;
    }

    foreach (var key in changes.InsertedKeys)
    {
        Debug.WriteLine($"Player placed at a new competition: {key}: {dict[key]}");
    }
});

// Build a RealmQuery that searches the Dictionary type
var snakeCase4LifeEnemies = realm.All.Filter("GamePlayStats['playerNemesis'] == 'snakeCase4Life'");

// snakeCase4Life has changed their attitude and are no longer
// at odds with anyone
realm.Write(() =>
{
    foreach (var player in snakeCase4LifeEnemies)
    {
        player.GamePlayStats.Remove("playerNemesis");
    }
});
```
:::
::::

## Mixed

Realm's Mixed type allows any Realm primitive type to be stored in the
database, helping developers when strict type-safety isn't appropriate.
Developers may find this useful when dealing with data they don't have
total control over – like receiving data and values from a third-party
API. Mixed data types are also useful when dealing with legacy states
that were stored with the incorrect types. Converting the type could
break other APIs and create considerable work. With Mixed types,
developers can avoid this difficulty and save hours of time.

We believe Mixed data types will be especially valuable for users who
want to sync data between Realm and MongoDB Atlas. MongoDB's
document-based data model allows a single field to support many types
across documents. For users syncing data between Realm and Atlas, the
new Mixed type allows developers to persist data of any valid Realm
primitive type, or any Realm Object class reference. Developers don't
risk crashing their app because a field value violated type-safety rules
in Realm.

::::tabs
:::tab[]{tabid="Kotlin"}
``` kotlin
import android.util.Log
import io.realm.*
import io.realm.kotlin.where

open class Distributor : RealmObject() {
    var name: String = ""
    var transitPolicy: String = ""
}

open class Business : RealmObject() {
    var name: String = ""
    var deliveryMethod: String = ""
}

open class Individual : RealmObject() {
    var name: String = ""
    var salesTerritory: String = ""
}

open class Palette(var owner: RealmAny = RealmAny.nullValue()) : RealmObject() {
    var scanId: String? = null
    open fun ownerToString(): String {
        return when (owner.type) {
            RealmAny.Type.NULL -> {
                "no owner"
            }
            RealmAny.Type.STRING -> {
                owner.asString()
            }
            RealmAny.Type.OBJECT -> {
                when (owner.valueClass) {
                    is Business -> {
                        val business = owner.asRealmModel(Business::class.java)
                        business.name
                    }
                    is Distributor -> {
                        val distributor = owner.asRealmModel(Distributor::class.java)
                        distributor.name
                    }
                    is Individual -> {
                        val individual = owner.asRealmModel(Individual::class.java)
                        individual.name
                    }
                    else -> "unknown type"
                }
            }
            else -> {
                "unknown type"
            }
        }
    }
}

realm.executeTransaction { r: Realm ->
    val newDistributor = r.copyToRealm(Distributor().apply {
        name = "Warehouse R US"
        transitPolicy = "Onsite Truck Pickup"
    })
    val paletteOne = r.copyToRealm(Palette().apply {
        scanId = "A1"
    })
    // Add the owner of the palette as an object reference to another Realm class
    paletteOne.owner = RealmAny.valueOf(newDistributor)
    val newBusiness = r.copyToRealm(Business().apply {
        name = "Mom and Pop"
        deliveryMethod = "Cheapest Private Courier"
    })
    val paletteTwo = r.copyToRealm(Palette().apply {
        scanId = "B2"
        owner = RealmAny.valueOf(newBusiness)
    })
    val newIndividual = r.copyToRealm(Individual().apply {
        name = "Traveling Salesperson"
        salesTerritory = "DC Corridor"
    })
    val paletteThree = r.copyToRealm(Palette().apply {
        scanId = "C3"
        owner = RealmAny.valueOf(newIndividual)
    })
}

// Get a reference to palette one
val paletteOne = realm.where()
        .equalTo("scanId", "A1")
        .findFirst()!!

// Extract underlying Realm Object from RealmAny by casting it RealmAny.Type.OBJECT
val ownerPaletteOne: Palette = paletteOne.owner.asRealmModel(Palette::class.java)
Log.v("EXAMPLE", "Owner of Palette One: " + ownerPaletteOne.ownerToString())

// Get a reference to the palette owned by Traveling Salesperson
// so that you can remove ownership - they're broke!
val salespersonPalette = realm.where()
        .equalTo("owner.name", "Traveling Salesperson")
        .findFirst()!!

val salesperson = realm.where()
        .equalTo("name", "Traveling Salesperson")
        .findFirst()

realm.executeTransaction { r: Realm ->
    salespersonPalette.owner = RealmAny.nullValue()
}

val paletteTwo = realm.where()
        .equalTo("scanId", "B2")
        .findFirst()!!

// Set up a listener to see when Ownership changes for relabeling of palettes
val listener = RealmObjectChangeListener { changedPalette: Palette, changeSet: ObjectChangeSet? ->
    if (changeSet != null && changeSet.changedFields.contains("owner")) {
        Log.i("EXAMPLE",
                "Palette $'paletteTwo.scanId' has changed ownership.")
    }
}

// Observe object notifications.
paletteTwo.addChangeListener(listener)
```
:::
:::tab[]{tabid="Swift"}
``` swift
import Foundation
import RealmSwift

class Distributor: Object {
    @objc dynamic var name: String?
    @objc dynamic var transitPolicy: String?
}

class Business: Object {
    @objc dynamic var name: String?
    @objc dynamic var deliveryMethod: String?
}

class Individual: Object {
    @objc dynamic var name: String?
    @objc dynamic var salesTerritory: String?
}

class Palette: Object {
    @objc dynamic var scanId: String?
    let owner = RealmProperty()
    var ownerName: String? {
        switch owner.value {
            case .none:
                return "no owner"
            case .string(let value):
                return value
            case .object(let object):
                switch object {
                    case let obj as Business: return obj.name
                    case let obj as Distributor: return obj.name
                    case let obj as Individual: return obj.name
                    default: return "unknown type"
                }
        default: return "unknown type"
        }
    }
}

let realm = try! Realm()
try! realm.write {
    let newDistributor = Distributor()
    newDistributor.name = "Warehouse R Us"
    newDistributor.transitPolicy = "Onsite Truck Pickup"

    let paletteOne = Palette()
    paletteOne.scanId = "A1"
    paletteOne.owner.value = .object(newDistributor)

    let newBusiness = Business()
    newBusiness.name = "Mom and Pop"
    newBusiness.deliveryMethod = "Cheapest Private Courier"

    let paletteTwo = Palette()
    paletteTwo.scanId = "B2"
    paletteTwo.owner.value = .object(newBusiness)

    let newIndividual = Individual()
    newIndividual.name = "Traveling Salesperson"
    newIndividual.salesTerritory = "DC Corridor"

    let paletteThree = Palette()
    paletteTwo.scanId = "C3"
    paletteTwo.owner.value = .object(newIndividual)
}

// Get a Reference to PaletteOne
let paletteOne = realm.objects(Palette.self)
    .filter("name == 'A1'").first

// Extract underlying Realm Object from AnyRealmValue field
let ownerPaletteOneName = paletteOne?.ownerName
print("Owner of Palette One: \(ownerPaletteOneName ?? "not found")");

// Get a reference to the palette owned by Traveling Salesperson
// so that you can remove ownership - they're broke!

let salespersonPalette = realm.objects(Palette.self)
    .filter("owner.name == 'Traveling Salesperson").first

let salesperson = realm.objects(Individual.self)
    .filter("name == 'Traveling Salesperson'").first

try! realm.write {
    salespersonPalette?.owner.value = .none
}

let paletteTwo = realm.objects(Palette.self)
    .filter("name == 'B2'")
```
:::
:::tab[]{tabid="JavaScript"}
``` javascript
const DistributorSchema = {
  name: "Distributor",
  properties: {
    name: "string",
    transitPolicy: "string",
  },
};

const BusinessSchema = {
  name: "Business",
  properties: {
    name: "string",
    deliveryMethod: "string",
  },
};

const IndividualSchema = {
  name: "Individual",
  properties: {
    name: "string",
    salesTerritory: "string",
  },
};

const PaletteSchema = {
  name: "Palette",
  properties: {
    scanId: "string",
    owner: "mixed",
  },
};

realm.write(() => {

  const newDistributor;
  newDistributor = realm.create("Distributor", {
    name: "Warehouse R Us",
    transitPolicy: "Onsite Truck Pickup"
  });

  const paletteOne;
  paletteOne = realm.create("Palette", {
    scanId: "A1",
    owner: newDistributor
  });

  const newBusiness;
  newBusiness = realm.create("Business", {
    name: "Mom and Pop",
    deliveryMethod: "Cheapest Private Courier"
  });

  const paletteTwo;
  paletteTwo = realm.create("Palette", {
    scanId: "B2",
    owner: newBusiness
  });

  const newIndividual;
  newIndividual = realm.create("Business", {
    name: "Traveling Salesperson",
    salesTerritory: "DC Corridor"
  });

  const paletteThree;
  paletteThree = realm.create("Palette", {
    scanId: "C3",
    owner: newIndividual
  });
});

//Get a Reference to PaletteOne
const paletteOne = realm.objects("Palette")
  .filtered(`scanId == 'A1'`);

//Extract underlying Realm Object from mixed field
const ownerPaletteOne = paletteOne.owner;
console.log(`Owner of PaletteOne: " ${ownerPaletteOne.name}!`);

//Get a reference to the palette owned by Traveling Salesperson
// so that you can remove ownership - they're broke!

const salespersonPalette = realm.objects("Palette")
    .filtered(`owner.name == 'Traveling Salesperson'`);

let salesperson = realm.objects("Individual")
    .filtered(`name == 'Traveling Salesperson'`)

realm.write(() => {
    salespersonPalette.owner = null
});

// Observe the palette to know when the owner has changed for relabeling

let paletteTwo = realm.objects("Palette")
    .filtered(`scanId == 'B2'`)

function onOwnerChange(palette, changes) {
    changes.changedProperties.forEach((prop) => {
      if(prop == owner){
      console.log(`Palette "${palette.scanId}" has changed ownership to "${palette[prop]}"`);
      }
    });
}

paletteTwo.addListener(onOwnerChange);
```
:::
:::tab[]{tabid=".NET"}
``` csharp
public class Distributor : RealmObject
{
    public string Name { get; set; }
    public string TransitPolicy { get; set; }
}

public class Business : RealmObject
{
    public string Name { get; set; }
    public string DeliveryMethod { get; set; }
}

public class Individual : RealmObject
{
    public string Name { get; set; }
    public string SalesTerritory { get; set; }
}

public class Palette : RealmObject
{
    public string ScanId { get; set; }
    public RealmValue Owner { get; set; }

    public string OwnerName
    {
        get
        {
            if (Owner.Type != RealmValueType.Object)
            {
                return null;
            }

            var ownerObject = Owner.AsRealmObject();
            if (ownerObject.ObjectSchema.TryFindProperty("Name", out _))
            {
                return ownerObject.DynamicApi.Get("Name");
            }

            return "Owner has no name";
        }
    }
}

realm.Write(() =>
{
    var newDistributor = realm.Add(new Distributor
    {
        Name = "Warehouse R Us",
        TransitPolicy = "Onsite Truck Pickup"
    });

    realm.Add(new Palette
    {
        ScanId = "A1",
        Owner = newDistributor
    });

    var newBusiness =realm.Add(new Business
    {
        Name = "Mom and Pop",
        DeliveryPolicy = "Cheapest Private Courier"
    });

    realm.Add(new Palette
    {
        ScanId = "B2",
        Owner = newBusiness
    });

    var newIndividual = realm.Add(new Individual
    {
        Name = "Traveling Salesperson",
        SalesTerritory = "DC Corridor"
    });

    realm.Add(new Palette
    {
        ScanId = "C3",
        Owner = newIndividual
    });
});

// Get a Reference to PaletteOne
var paletteOne = realm.All()
                      .Single(t => t.ScanID == "A1");

// Extract underlying Realm Object from mixed field
var ownerPaletteOne = paletteOne.Owner.AsRealmObject();
Debug.WriteLine($"Owner of Palette One is {ownerPaletteOne.OwnerName}");

// Get a reference to the palette owned by Traveling Salesperson
// so that you can remove ownership - they're broke!

var salespersonPalette = realm.All()
                              .Filter("Owner.Name == 'Traveling Salesperson'")
                              .Single();

realm.Write(() =>
{
    salespersonPalette.Owner = RealmValue.Null;
});

// Set up a listener to observe changes in ownership so you can relabel the palette

var paletteTwo = realm.All()
                      .Single(p => p.ScanID == "B2");

paletteTwo.PropertyChanged += (sender, args) =>
{
    if (args.PropertyName == nameof(Pallette.Owner))
    {
        Debug.WriteLine($"Palette {paletteTwo.ScanId} has changed ownership {paletteTwo.OwnerName}");
    }
};
```
:::
::::

## Sets

Sets allow developers to store an unordered array of unique values. This
new data type in Realm opens up powerful querying and mutation
capabilities with only a few lines of code.

With sets, you can compare data and quickly find matches. Sets in Realm
have built-in methods for filtering and writing to a set that are unique
to the type. Unique methods on the Set type include, isSubset(),
contains(), intersects(), formIntersection, and formUnion(). Aggregation
functions like min(), max(), avg(), and sum() can be used to find
averages, sums, and similar.

Sets in Realm have the potential to eliminate hundreds of lines of
gluecode. Consider an app that suggests expert speakers from different
areas of study, who can address a variety of specific topics. The
developer creates two classes for this use case: Expert and Topic. Each
of these classes has a Set field of strings which defines the
disciplines the user is an expert in, and the fields that the topic
covers.

Sets will make the predicted queries easy for the developer to
implement. An app user who is planning a Speaker Panel could see all
experts who have knowledge of both "Autonomous Vehicles" and "City
Planning." The application could also run a query that looks for experts
in one or more of these disciples by using the built-in intersect
method, and the user can use results to assemble a speaker panel.

Developers who are using [MongoDB Realm
Sync to keep data up-to-date
between Realm and MongoDB Atlas are able to keep the semantics of a Set
in place even when synchronizing data.

You can depend on the enforced uniqueness among the values of a Set.
There's no need to check the array for a value match before performing
an insertion, which is a common implementation pattern that any user of
SQLite will be familiar with. The operations performed on Realm Set data
types will be synced and translated to documents using the
$addToSet
group of operations on MongoDB, preserving uniqueness in arrays.

::::tabs
:::tab]{tabid="Kotlin"}
``` kotlin
import android.util.Log
import io.realm.*
import io.realm.kotlin.where

open class Expert : RealmObject() {
    var name: String = ""
    var email: String = ""
    var disciplines: RealmSet = RealmSet()
}

open class Topic : RealmObject() {
    var name: String = ""
    var location: String = ""
    var discussionThemes: RealmSet = RealmSet()
    var panelists: RealmList = RealmList()
}

realm.executeTransaction { r: Realm ->
    val newExpert = r.copyToRealm(Expert())
    newExpert.name = "Techno King"
    // get the RealmSet field from the object we just created
    val disciplineSet = newExpert.disciplines
    // add value to the RealmSet
    disciplineSet.add("Trance")
    disciplineSet.add("Meme Coins")
    val topic = realm.copyToRealm(Topic())
    topic.name = "Bitcoin Mining and Climate Change"
    val discussionThemes = topic.discussionThemes
    // Add a list of themes
    discussionThemes.addAll(listOf("Memes", "Blockchain", "Cloud Computing",
            "SNL", "Weather Disasters from Climate Change"))
}

// find experts for a discussion topic and add them to the panelists list
val experts: RealmResults = realm.where().findAll()
val topic = realm.where()
        .equalTo("name", "Bitcoin Mining and Climate Change")
        .findFirst()!!
topic.discussionThemes.forEach { theme ->
    experts.forEach { expert ->
        if (expert.disciplines.contains(theme)) {
            topic.panelists.add(expert)
        }
    }
}

//observe the discussion themes set for any changes in the set
val discussionTopic = realm.where()
        .equalTo("name", "Bitcoin Mining and Climate Change")
        .findFirst()
val anotherDiscussionThemes = discussionTopic?.discussionThemes
val changeListener = SetChangeListener { collection: RealmSet,
                                         changeSet: SetChangeSet ->
    Log.v(
            "EXAMPLE",
            "New discussion themes has been added: ${changeSet.numberOfInsertions}"
    )
}

// Observe set notifications.
anotherDiscussionThemes?.addChangeListener(changeListener)

// Techno King is no longer into Meme Coins - remove the discipline
realm.executeTransaction {
    it.where()
            .equalTo("name", "Techno King")
            .findFirst()?.let { expert ->
        expert.disciplines.remove("Meme Coins")
    }
}
```
:::
:::tab[]{tabid="Swift"}
``` swift
import Foundation
import RealmSwift

class Expert: Object {
    @objc dynamic var name: String?
    @objc dynamic var email: String?
    let disciplines = MutableSet()
}

class Topic: Object {
    @objc dynamic var name: String?
    @objc dynamic var location: String?
    let discussionThemes = MutableSet()
    let panelists = List()
}

let realm = try! Realm()
try! realm.write {
    let newExpert = Expert()
    newExpert.name = "Techno King"
    newExpert.disciplines.insert("Trace")
    newExpert.disciplines.insert("Meme Coins")
    realm.add(newExpert)

    let topic = Topic()
    topic.name = "Bitcoin Mining and Climate Change"
    topic.discussionThemes.insert("Memes")
    topic.discussionThemes.insert("Blockchain")
    topic.discussionThemes.insert("Cloud Computing")
    topic.discussionThemes.insert("SNL")
    topic.discussionThemes.insert("Weather Disasters from Climate Change")
    realm.add(topic)
}

// find experts for a discussion topic and add them to the panelists list

let experts = realm.objects(Expert.self)
let topic = realm.objects(Topic.self)
    .filter("name == 'Bitcoin Mining and Climate Change'").first
guard let topic = topic else { return }
let discussionThemes = topic.discussionThemes

for expert in experts where expert.disciplines.intersects(discussionThemes) {
    try! realm.write {
        topic.panelists.append(expert)
    }
}

// Observe the discussion themes set for new entries
let notificationToken = discussionThemes.observe { changes in
    switch changes {
    case .update(_, _, let insertions, _):
        for insertion in insertions {
            let insertedTheme = discussionThemes[insertion]
            print("A new discussion theme has been added:  \(insertedTheme)")
        }
    default:
        print("Only handling updates")
    }
}

// Techno King is no longer into Meme Coins - remove the discipline
try! realm.write {
    newExpert.disciplines.remove("Meme Coins")
}
```
:::
:::tab[]{tabid="JavaScript"}
``` javascript
const ExpertSchema = {
  name: "Expert",
  properties: {
    name: "string?",
    email: "string?",
    disciplines: "string<>"
  },
};

const TopicSchema = {
  name: "Topic",
  properties: {
    name: "string?",
    locaton: "string?",
    discussionThemes: "string<>", //<> indicate a Set datatype
    panelists: "Expert[]"
  },
};

realm.write(() => {
  let newExpert;
  newExpert = realm.create("Expert", {
    name: "Techno King",
    disciplines: ["Trance", "Meme Coins"],
  });

  let topic;
  topic = realm.create("Topic", {
    name: "Bitcoin Mining and Climate Change",
    discussionThemes: ["Memes", "Blockchain", "Cloud Computing",
    "SNL", "Weather Disasters from Climate Change"],
  });
});

// find experts for a discussion topic and add them to the panelists list
const experts = realm.objects("Expert");

const topic = realm.objects("Topic").filtered(`name ==
  'Bitcoin Mining and Climate Change'`);
const discussionThemes = topic.discussionThemes;

for (int i = 0; i < discussionThemes.size; i++) {
    for (expert in experts){
        if(expert.disciplines.has(dicussionThemes[i]){
            realm.write(() => {
                realm.topic.panelists.add(expert)
            });
        }
    }
}

// Set up the listener to watch for new discussion themes added to the topic
  discussionThemes.addListener((changedDiscussionThemes, changes) => {
     changes.insertions.forEach((index) => {
       const insertedDiscussion = changedDiscussionThemes[index];
       console.log(`"A new discussion theme has been added: " ${insertedDiscussion}!`);
  });

// Techno King is no longer into Meme Coins - remove the discipline
newExpert.disciplines.delete("Meme Coins")
```
:::
:::tab[]{tabid=".NET"}
``` csharp
public class Expert : RealmObject
{
    public string Name { get; set; }
    public string Email { get; set; }

    [Required]
    public ISet Disciplines { get; }
}

public class Topic : RealmObject
{
    public string Name { get; set; }
    public string Location { get; set; }

    [Required]
    public ISet DiscussionThemes { get; }

    public IList Panelists { get; }
}

realm.Write(() =>
{
    var newExpert = realm.Add(new Expert
    {
        Name = "Techno King"
    });

    newExpert.Disciplines.Add("Trance");
    newExpert.Disciplines.Add("Meme Coins");

    var topic = realm.Add(new Topic
    {
        Name = "Bitcoin Mining and Climate Change"
    });

    topic.DiscussionThemes.Add("Memes");
    topic.DiscussionThemes.Add("Blockchain");
    topic.DiscussionThemes.Add("Cloud Computing");
    topic.DiscussionThemes.Add("SNL");
    topic.DiscussionThemes.Add("Weather Disasters from Climate Change");
});

// find experts for a discussion topic and add them to the panelists list
var experts = realm.All();
var topic = realm.All()
    .Where(t => t.Name == "Bitcoin Mining and Climate Change");

foreach (expert in experts)
{
    if (expert.Disciplines.Overlaps(topic.DiscussionThemes))
    {
        realm.Write(() =>
        {
            topic.Panelists.Add(expert);
        });
    }
}

// Set up the listener to watch for new dicussion themes added to the topic
var token = topic.DiscussionThemes
    .SubscribeForNotifications((collection, changes, error) =>
{
    foreach (var i in changes.InsertedIndices)
    {
        var insertedDiscussion = collection[i];
        Debug.WriteLine($"A new discussion theme has been added to the topic {insertedDiscussion}");
    }
});

// Techno King is no longer into Meme Coins - remove the discipline
newExpert.Disciplines.Remove("Meme Coins")
```
:::
::::

## UUIDs

The Realm SDKs also now support the ability to generate and persist
Universally Unique Identifiers (UUIDs) natively. UUIDs are ubiquitous in
app development as the most common type used for primary keys. As a
128-bit value, they have become the default for distributed storage of
data in mobile to cloud application architectures - making collisions
unheard of.

Previously, Realm developers would generate a UUID and then cast it as a
string to store in Realm. But we saw an opportunity to eliminate
repetitive code, and with the release of UUID data types, Realm comes
one step closer to boilerplate-free code.

Like with the other new data types, the release of UUIDs also brings
Realm's data types to parity with MongoDB. Now mobile application
developers will be able to set UUIDs on both ends of their distributed
datastore, and can rely on Realm Sync to perform the replication.

::::tabs
:::tab[]{tabid="Kotlin"}
``` kotlin
import io.realm.Realm
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmField
import java.util.UUID;
import io.realm.kotlin.where

open class Task: RealmObject() {
    @PrimaryKey
    @RealmField("_id")
    var id: UUID = UUID.randomUUID()
    var name: String = ""
    var owner: String= ""
}

realm.executeTransaction { r: Realm ->
    // UUID field is generated automatically in the class constructor
    val newTask = r.copyToRealm(Task())
    newTask.name = "Update to use new Data Types"
    newTask.owner = "Realm Developer"
}

val taskUUID: Task? = realm.where()
        .equalTo("_id", "38400000-8cf0-11bd-b23e-10b96e4ef00d")
        .findFirst()
```
:::
:::tab[]{tabid="Swift"}
``` swift
import Foundation
import RealmSwift

class Task: Object {
    @objc dynamic var _id = UUID()
    @objc dynamic var name: String?
    @objc dynamic var owner: String?
    override static func primaryKey() -> String? {
        return "_id"
    }

    convenience init(name: String, owner: String) {
        self.init()
        self.name = name
        self.owner = owner
    }
}

let realm = try! Realm()
try! realm.write {
    // UUID field is generated automatically in the class constructor
    let newTask =
    Task(name: "Update to use new Data Types", owner: "Realm Developers")
}

let uuid = UUID(uuidString: "38400000-8cf0-11bd-b23e-10b96e4ef00d")

// Set up the query to retrieve the object with the UUID
let predicate = NSPredicate(format: "_id = %@", uuid! as CVarArg)

let taskUUID = realm.objects(Task.self).filter(predicate).first
```
:::
:::tab[]{tabid="JavaScript"}
``` javascript
const { UUID } = Realm.BSON;

const TaskSchema = {
  name: "Task",
  primaryKey: "_id",
  properties: {
    _id: "uuid",
    name: "string?",
    owner: "string?"
  },
};

let task;

realm.write(() => {
  task = realm.create("Task", {
    _id: new UUID(),
    name: "Update to use new Data Type",
    owner: "Realm Developers"
  });

let searchUUID = UUID("38400000-8cf0-11bd-b23e-10b96e4ef00d");

const taskUUID = realm.objects("Task")
  .filtered(`_id == $0`, searchUUID);
```
:::
:::tab[]{tabid=".NET"}
``` csharp
public class Task : RealmObject
{
    [PrimaryKey]
    [MapTo("_id")]
    public Guid Id { get; private set; } = Guid.NewGuid();
    public string Name { get; set; }
    public string Owner { get; set; }
}

realm.Write(() =>
{
    realm.Add(new Task
    {
        PlayerHandle = "Update to use new Data Type",
        Owner = "Realm Developers"
    });
});

var searchGUID = Guid.Parse("38400000-8cf0-11bd-b23e-10b96e4ef00d");

var taskGUID = realm.Find(searchGUID);
```
:::
::::

## Conclusion

From the beginning, Realm's engineering team has believed that the best
line of code is the one a developer doesn't need to write. With the
release of these unique types for mobile developers, we're eliminating
the workarounds – the boilerplate code and negative impact on CPU and
memory – that are commonly required with certain data structures. And
we're doing it in a way that's idiomatic to the platform you're building
on.

By making it simple to query, store, and sync your data, all in the
format you need, we hope we've made it easier for you to focus on
building your next great app.

Stay tuned by following [@realm on Twitter.

Want to Ask a Question? Visit our
Forums.

Want to be notified about upcoming Realm events, like talks on SwiftUI
Best Practices or our new Kotlin Multiplatform SDK? Visit our Global
Community Page.