skip to Main Content

Working on React Native Realm database ("realm": "11.0.0"), I can’t make Embedded Objects documented here work.

The error I have is :

 ERROR  Exception in HostFunction: Embedded objects cannot be created directly.

Please find below the code you can copy/past to reproduce the problem if you like. If you uncomment "embedded: true", this one-to-many relationship example works.

import React from "react";
import { View, Text } from "react-native";
import Realm from "realm";

export class Project extends Realm.Object<Project> {
  public _id: number;
  public name: string;
  public tasks: Realm.List<Task>;

  static schema = {
    name: "Project",
    primaryKey: "_id",
    properties: {
      _id: "int",
      name: "string",
      tasks: { type: "list", objectType: "Task" },
    },
  };
}

export class Task extends Realm.Object<Task> {
  public description: string;

  static schema = {
    name: "Task",
    embedded: true, // uncomment
    properties: {
      description: "string",
    },
  };
}

(async () => {
  let realm: any;

  try {
    realm = await Realm.open({
      inMemory: true,
      schema: [Project, Task],
    });
  } catch (e) {
    console.error(e.message);
  }

  try {
    realm.write(() => {
      const t1 = realm.create(Task, {
        description: "T1",
      });

      const t2 = realm.create(Task, {
        description: "T2",
      });

      realm.create(Project, {
        _id: 1,
        name: "P1",
        tasks: [t1, t2],
      });
    });
  } catch (e) {
    console.error(e.message);
  }

  console.log(JSON.stringify(realm.objects(Project), null, 3));

  realm.close();
})();

export const App = () => {
  return (
    <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
      <Text style={{ fontSize: 25 }}>Please look at the console</Text>
    </View>
  );
};

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to Jay answer and after reading the doc more carefully, I changed the creation of Project and its embedded Tasks like this and it works :

    realm.write(() => {
      realm.create("Project", {
        _id: 1,
        name: "P1",
        tasks: [
          {
            description: "T1",
          },
          {
            description: "T2",
          },
        ],
      });
    });
    

    But I am still unable to create embedded object when I model objects with class and constructor or class and static generate(). If you have a working example of this kind, please post it.

    UPDATE (25/03/2023) : To be more explicit, how to modify the code below to make the embedded feature work ? But if possible, TASK being a class with a constructor.

    Without the "embedded: true," line, the output of this code is:

    {"_id": "641e5fdebde518d4ac0e7665", "name": "P1", "tasks": [{"description": "T1"}, {"description": "T2"}]}

    With the "embedded: true," the output of this code is:

    ERROR Exception in HostFunction: Embedded objects cannot be created directly.

    import React from "react";
    import { View, Text } from "react-native";
    import Realm from "realm";
    
    export class Project extends Realm.Object<Project> {
      public _id: Realm.BSON.ObjectId;
      public name: string;
      public tasks: Realm.List<Task>;
    
      static schema = {
        name: "Project",
        primaryKey: "_id",
        properties: {
          _id: "objectId",
          name: "string",
          tasks: { type: "list", objectType: "Task" },
        },
      };
    
      constructor(realm: Realm, name: string, tasks: Task[] = []) {
        super(realm, {
          _id: new Realm.BSON.ObjectId(),
          name: name,
          tasks: tasks,
        });
      }
    }
    
    export class Task extends Realm.Object<Task> {
      public description: string;
    
      static schema = {
        name: "Task",
        embedded: true, // <==============================
        properties: {
          description: "string",
        },
      };
    
      constructor(realm: Realm, description: string) {
        super(realm, {
          description: description,
        });
      }
    }
    
    (async () => {
      let realm: any;
    
      try {
        realm = await Realm.open({
          inMemory: true,
          schema: [Project, Task],
        });
      } catch (e) {
        console.error(e.message);
      }
    
      try {
        realm.write(() => {
          new Project(realm, "P1", [new Task(realm, "T1"), new Task(realm, "T2")]);
        });
      } catch (e) {
        console.error(e.message);
      }
    
      for (const item of realm.objects(Project)) {
        console.log(item.toJSON());
      }
    
      realm.close();
    })();
    
    export const App = () => {
      return (
        <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
          <Text style={{ fontSize: 25 }}>Please look at the console</Text>
        </View>
      );
    };
    

  2. There’s an important differentiation between a Realm Object and a Realm Embedded object:

    A Realm object is a separate, independent object that is directly managed by Realm.

    Whereas an Embedded Object is just that; embedded within a parent object. It is not a separate, independent object and is only managed by Realm through its parent object. Because of that, Embedded Objects cannot be directly written to Realm.

    An embedded object does not exist without it’s parent object. It cannot be stored in Realm directly; it has to be added to it’s parent and then the parent must be stored (or it could be added to an already existing parent object).

    Big picture is that Embedded Objects are actually part of the parent’s schema and when the parent is deleted, so are it’s embedded objects.

    Additionally, Embedded Objects can only be queried through the parent object; so for example, suppose a Person object has an embedded Dog object. If you wanted to look for a person who has a dog named spot, it would be (pseudo code)

    let somePerson = realm.query on the personObject.embeddedDog.name == "spot"
    

    note that

    Embedded objects map to embedded documents in the parent type’s
    schema . This behavior differs from regular Realm objects, which map
    to their own MongoDB collection.

    so this

    schema: [Project, Task],
    

    won’t work as a Task is part of the Project‘s schema

    EDIT

    An example would be a business that has several addresses. The address themselves don’t need to be separatly managed objects as they are directly tied to the parent business.

    Here’s a business object which will contain several embedded address objects

    const BusinessSchema = {
      name: "Business",
      primaryKey: "_id",
      properties: {
        _id: "objectId",
        name: "string",
        addresses: { type: "list", objectType: "Address" },//array of embedded objects
      },
    };
    

    and then the embedded address objects look like this

    const AddressSchema = {
      name: "Address",
      embedded: true, // default: false
      properties: {
        street: "string?",
        city: "string?",
        country: "string?",
        postalCode: "string?",
      },
    };
    

    note that embedded objects must be set to embedded: true and then also insure the embedded object does not have a primary key.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search