Realm-js: Fail to create / push an object with linkingObjects to its parent

Created on 7 Nov 2017  路  16Comments  路  Source: realm/realm-js

Questions: In another project, I can use linkingObjects well. But I don't know why I cannot create or push object with linkingObjects to its parent for now. Once I create or push object linkingObjects to its parent, the UI freezes and the app cannot run. I force quit the app and reenter it. The UI still freezes and the app cannot run.

Please help.

Expected Results

It can update / create the object

Actual Results

It cannot update / create the object. The UI freezes even after force quit and reopen the app. And the app cannot run.

Steps to Reproduce

1) Run the below code
2) tap "Click me."

Code Sample

I modified a bit of your example to simulate my case and I got the same result.

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View
} from 'react-native';

const Realm = require('realm');

const CarSchema = {
  name: 'Car',
  properties: {
    make: 'string',
    model: 'string',
    miles: { type: 'int', default: 0 },
    owners: { type: 'linkingObjects', objectType: 'Person', property: 'cars' } // What I added
  }
};
const PersonSchema = {
  name: 'Person',
  properties: {
    name: 'string',
    birthday: 'date',
    cars: 'Car[]',
    picture: 'data?'
  }
};

export default class App extends Component {

  Update = () => {
    Realm.open({ schema: [CarSchema, PersonSchema] })
      .then(realm => {
        realm.write(() => {
          const myCar = realm.create('Car', {
            make: 'Honda',
            model: 'Civic',
            miles: 1000,
          });
          myCar.miles += 20;
        });

        const cars = realm.objects('Car').filtered('miles > 1000');

        realm.write(() => {
          const myCar = realm.create('Person', {
            name: 'Adrian',
            birthday: new Date(),
            cars: [{
              make: 'BMW',
              model: '8310',
              miles: 200
            }]
          });
        });
        alert(JSON.stringify(realm.objects('Car')))
      });
  }

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', }}>
        <Text onPress={() => this.Update()} style={{ alignSelf: 'center' }}>
          Click me.
        </Text>
      </View>
    );
  }
}

Version of Realm and Tooling

  • Realm JS SDK Version: 2.0.3
  • React Native: 0.50.1
  • Client OS & Version: Android 7.0, iOS 11 (Both simulator and real device)
  • Which debugger for React Native: Google Chrome (It happens even without debugger)
O-Community Reproduction-Required T-Bug

All 16 comments

And you don't observe it when you remove owners? Does it also freeze if the BWM is created separately and added to Adrian's cars as a Realm object?

I rewrite the code in the following way, by separating the creation of Car and Person. And then link them together. It does not freeze after trigger the linkage, but neither Car and Person object shows their linkage after refresh.

Once I click "Link Car to Person", a yellow warning message is prompted.

"Possible Unhandled Promise Rejection (id: 1): Error: properties must be of type 'object', got (undefined)" ==> Why so? Please help

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View
} from 'react-native';

const Realm = require('realm');

const CarSchema = {
  name: 'Car',
  properties: {
    make: 'string',
    model: 'string',
    miles: { type: 'int', default: 0 },
    owners: { type: 'linkingObjects', objectType: 'Person', property: 'cars' }
  }
};
const PersonSchema = {
  name: 'Person',
  properties: {
    name: 'string',
    birthday: 'date',
    cars: 'Car[]',
    picture: 'data?'
  }
};

export default class App extends Component {

  state = {
    cars: null,
    people: null
  }

  createPerson = () => {
    Realm.open({ schema: [CarSchema, PersonSchema] })
      .then(realm => {
        const myCar = realm.objects('Car')[0]
        realm.write(() => {
          realm.create('Person', {
            name: 'Adrian',
            birthday: new Date(),
            picture: null
          });
        })
      })
  }

  createCar = () => {
    Realm.open({ schema: [CarSchema, PersonSchema] })
      .then(realm => {
        realm.write(() => {
          realm.create('Car', {
            make: 'Honda',
            model: 'Civic',
            miles: 1000,
          });
        })
      })
  }

  linkCarToPerson = () => {
    Realm.open({ schema: [CarSchema, PersonSchema] })
      .then(realm => {
        const myPerson = realm.create('Person')[0]
        const myCar = realm.create('Car')[0]
        realm.write(() => {
          myPerson.cars.push(myCar)
        })
      })
  }

  componentWillMount() {
    Realm.open({ schema: [CarSchema, PersonSchema] })
      .then(realm => {
        this.setState({
          cars: realm.objects('Car')[0],
          people: realm.objects('Person')[0],
        })
      })
  }

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', }}>
        <Text onPress={() => this.createCar()} style={{ alignSelf: 'center' }}>
          Create a Car
        </Text>
        <Text onPress={() => this.createPerson()} style={{ alignSelf: 'center', marginTop: 20 }}>
          Create a Person
        </Text>
        <Text onPress={() => this.linkCarToPerson()} style={{ alignSelf: 'center', marginTop: 20 }}>
          Link Car to Person
        </Text>
        <Text style={{ alignSelf: 'center', marginTop: 20 }}>
          Cars: {JSON.stringify(this.state.cars)}
        </Text>
        <Text style={{ alignSelf: 'center', marginTop: 20 }}>
          People: {JSON.stringify(this.state.people)}
        </Text>
      </View>
    );
  }
}


realm.create('Person')[0] will create a new object. I think you really mean realm.object('Person')[0].

Thanks, it should be realm.create('Person')[0].

But when I tried with the amended code, the objects cannot yet linked together.
I refreshed and see that both class become null

By the way, I tried below using the version 1.13.0 and 2.0.5 respectively.
The former runs well, but the latter has problem.
After I reload the page, I got a blank page.

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View
} from 'react-native';

const Realm = require('realm');



const CarSchema = {
  name: 'Car',
  properties: {
    make: 'string',
    model: 'string',
    miles: { type: 'int', default: 0 },
    owners: { type: 'linkingObjects', objectType: 'Person', property: 'cars' }
  }
};
const PersonSchema = {
  name: 'Person',
  properties: {
    name: 'string',
    birthday: 'date',
    cars: {type: 'list', objectType: 'Car'},
    picture: 'string'
  }
};

var realm = new Realm({schema: [CarSchema, PersonSchema], schemaVersion: 0 })

export default class App extends Component {

  state = {
    cars: null,
    people: null
  }

  createPerson = () => {
    realm.write(() => {
      realm.create('Person', {
        name: 'Adrian',
        birthday: new Date(),
        picture: "Hello"
      }
      )
    })
  }

  createCar = () => {
    realm.write(() => {
      realm.create('Car', {
        make: 'Honda',
        model: 'Civic',
        miles: 1000,
      })
    })
  }

  linkCarToPerson = () => {

    const myPerson = realm.objects('Person')[0]
    const myCar = realm.objects('Car')[0]
    try {
      realm.write(() => {
        myPerson.cars.push(myCar)
      })
    } catch (e) {
      alert(e);
    }
  }

  showCarOwner = () => {

        const myCar = realm.objects('Car')[0]
        alert(JSON.stringify(myCar.owners))
      }

  componentWillMount() {
    this.setState({
      cars: realm.objects('Car') ? realm.objects('Car'): null,
      people: realm.objects('Person')? realm.objects('Person'): null,
    })
  }

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', }}>
        <Text onPress={() => this.createCar()} style={{ alignSelf: 'center' }}>
          Create a Car
        </Text>
        <Text onPress={() => this.createPerson()} style={{ alignSelf: 'center', marginTop: 20 }}>
          Create a Person
        </Text>
        <Text onPress={() => this.linkCarToPerson()} style={{ alignSelf: 'center', marginTop: 20 }}>
          Link Car to Person
        </Text>
        <Text onPress={() => this.showCarOwner()} style={{ alignSelf: 'center', marginTop: 20 }}>
          Show the Car own
        </Text>
        <Text style={{ alignSelf: 'center', marginTop: 20 }}>
          Cars: {JSON.stringify(this.state.cars)}
        </Text>
        <Text style={{ alignSelf: 'center', marginTop: 20 }}>
          People: {JSON.stringify(this.state.people)}
        </Text>
      </View>
    );
  }
}


When you have a few minutes, it would be great if you tried to rewrite cars: {type: 'list', objectType: 'Car'} as cars: Car[]. It will only work for 2.0.x.

@kneth Did the schema format change from 2.0.x? Are changes documented somewhere?

Are you saying this is no longer valid schema ?
cars: {type: 'list', objectType: 'Car'},

@esutton The old one should work but cars: Car[] is the new one way. From 2.0.0, you can also have names: string[] so you don't have to create a wrapper for primitive types like numbers and strings :smile:.

@kneth

I love the shorthand and also the array of primitive type a lot.
2.0 is wonderful to me.

But as I cannot use 2.0.x, I cannot enjoy the new features.

@adrianchancy Please take a look at https://github.com/realm/realm-js/blob/master/tests/js/linkingobjects-tests.js and see if you are using Realm in a different way. If you are, I will be happy if you can contribute a test to expose any bugs.

I have the same problem. I think it might have to do with the .push method ... App screen freezes after push execution of linked object.

My schema:

class Log extends Realm.Object {}
Log.schema = {
    name: 'Log',
    properties: {
        date: 'date',
        elapsedSeconds: 'int',
        belongsTo: {type: 'linkingObjects', objectType: 'Activity', property: 'logs'}
    }
};

class Activity extends Realm.Object {}
Activity.schema = {
    name: 'Activity',
    primaryKey: 'id',
    properties: {
        id: {type: 'int', indexed: true},
        label: 'string',
        color: 'Color',
        logs: 'Log[]',
    }
};

Creation of a log object in the realm (works), fetching an activity from the realm(works):

realm.write(() => {
  let newLog = realm.create('Log', {date: new Date(), elapsedSeconds: elapsedSeconds});
  let editActivity = realm.objectForPrimaryKey('Activity', currentActivity.id);
  editActivity.logs.push(newLog); // <- this breaks it
});

If i rewrite the Activity schema property logs from logs: Log[] to logs: {type: 'list', objectType: 'Log'} it does not break anymore, but the logs entry of the Activity is empty after the push is executed.

Question on the side .. is there a special reason, why lists are objects of objects {0:{...}, 1:{...}} rather than arrays of objects [{...},{...}] ?

@JohnBra In #2370 I have added a test which is inspired by your code snippet. On node.js it does not fail.

Question on the side .. is there a special reason, why lists are objects of objects {0:{...}, 1:{...}} rather than arrays of objects [{...},{...}] ?

The reason is that the objects are not plain JS objects but "managed" objects. That is, a collection is not an array but an object which has most of the behaviour of an array.

@kneth thank you for the quick reply!

I have just tested it on a clean react-native app with not additional libs and code ... sadly it shows the same behaviour. Tested on device (Android 6) and emulator (iOS, iPhone X 12.2).

Steps to reproduce

  1. react-native init RealmTest
  2. cd RealmTest
  3. yarn add realm
  4. react-native link realm
  5. insert code below into App.js
  6. react-native run-ios or react-native run-android
  7. click on 'Click to add items to Realm' in the App

This is the code i used:


import React, {Component} from 'react';
import {StyleSheet, Text, View, TouchableHighlight} from 'react-native';

const Realm = require('realm');

const ColorSchema = {
  name: 'Color',
  primaryKey: 'id',
  properties: {
    id: {type: 'int', indexed: true},
    value: 'string'
  }
};


const LogSchema = {
  name: 'Log',
  properties: {
    date: 'date',
    elapsedSeconds: 'int',
    belongsTo: {type: 'linkingObjects', objectType: 'Activity', property: 'logs'}
  }
};

const ActivitySchema = {
  name: 'Activity',
  primaryKey: 'id',
  properties: {
    id: {type: 'int', indexed: true},
    label: 'string',
    color: 'Color',
    logs: 'Log[]'
  }
};

type Props = {};
export default class App extends Component<Props> {
  constructor(props) {
    super(props);
    this.state = { realm: null };
  }

  addItemsToRealm() {
    Realm.clearTestState();
    Realm.open({
      schema: [ActivitySchema, LogSchema, ColorSchema]
    }).then(realm => {
      realm.write(() => {
        let color = realm.create('Color', {id: 1, value: '#f00'});
        let activity = realm.create('Activity', {id: 1, label: 'Tmp Activity', color: color, logs:[]});

        // create log separately and then push
        //let log = realm.create('Log', {date: new Date(), elapsedSeconds: 42});
        //activity.logs.push(log);

        // create log in push command (best for my usecase)
        activity.logs.push({date: new Date(), elapsedSeconds: 42});

        // create activity after log including log in array (doesn't fit my usecase) also breaks
        //let activity = realm.create('Activity', {id: 1, label: 'Tmp Activity', color: color, logs:[log]});

        let getAllActivities = realm.objects('Activity');

        console.warn(getAllActivities);
      });
      this.setState({ realm });
    });
  }

  render() {
    const info = this.state.realm
        ? 'Number of Activities in this Realm: ' + this.state.realm.objects('Activity').length
        : 'Loading...';

    return (
        <View style={styles.container}>
          <TouchableHighlight onPress={() => this.addItemsToRealm()}>
            <Text>Click to add items to Realm</Text>
          </TouchableHighlight>
          <Text style={styles.welcome}>
            {info}
          </Text>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  }
});

I have included a few different ways to add a log to the activity object (see commented lines). None of those work.

I'd be happy to lend a you a hand testing on react-native @kneth

I guess that is something related to the object we got.
The issue is also discussed in https://github.com/realm/realm-js/issues/1532

@adrianchancy thanks for the help! It seems to be this exact problem ... in my applications it still breaks for both cases (remote debugging on and off)

Was this page helpful?
0 / 5 - 0 ratings