loading...

Realm Data Storage in React Native and Node.js

spencerlindemuth profile image SpencerLindemuth ・4 min read

  I've been developing a React Native application recently that stores some highly confidential information and it really made me stop and think about storage solutions. I'm traditionally a React web developer and I hadn't really stopped to consider the differences between web and native application development.

Differences

  When you create a traditional web application or site, your data persistence is kept to the back-end, and when you need more information, or need to save some, you send HTTP requests back and forth with the server who will handle that with a database connection. If you have something more short term you need to store, like a user or session id, you have a handful of options such as cookies, session storage, and HTML 5 LocalStorage. This is a fine solution that has functioned elegantly for years and something we are all overly familiar with. But when it comes to mobile app development things can be a little trickier. In mobile app development come a new set of hurdles that users on desktops aren't faced with. Spotty connections, limited data plans, and slower network speeds. These sort of hurdles can present a large barrier in terms of application performance. If you need to gather a feed of photos, there is still no way around making a network request, using data, and relying on an internet connection. But what if there is data or pages a client uses frequently and are an integral part of the app whether the client is at home on wifi or across the world and roaming? Now we need a quick, reliable and safe place to save this data with a little more longevity than cookies.

Built in storage with React Native

  React native comes with a built in storage solution that works across all platforms called AsyncStorage. Just like HTML 5's implementation of LocalStorage, it stores strings of data in a key - value pair, however AsyncStorage (as the name implies) stores data Asynchronously. The problem with AsyncStorage is that data can only be of the type "String" so data must constantly be converted back and forth, it cannot be reliably encrypted, and it can only store key - value pairs, which gets very complex for large data sets and the data can have no polymorphic relationships.

Enter Realm

  Realm is a storage system built for all platforms that uses an object oriented approach to databases, and can interface with Java, Swift, Objective-C, JavaScript, and .Net. Realm is also handy in the fact that it dynamically encrypts data depending on environment, using AES-256 standard encryption on an Android Device, the built in CommonCrypto library in iOS and the Crypto library included in Windows for native Windows applications. This means less code for you, and 200% more flawlessly running environments!

How to use Realm

  Getting started with Realm is easy. First create a new React Native project:

react-native init <project-name>

Then install Realm:

npm install --save realm

and then link Realm to your native project:

react-native link realm



So now we have a project created, lets see how to implement a super simple React Native App that utilizes Realm (from the Realm docs)

import Realm from 'realm';


//Create a simple class component
class <project-name> extends Component {
  constructor(props) {
    super(props);
    //initialize a piece of state that we will also be persisting
    this.state = { realm: null };
  }

  componentWillMount() {
    //open the realm database connection
    Realm.open({
      //define the schema. 
      schema: [{name: 'Dog', properties: {name: 'string'}}]
    }).then(realm => {
      realm.write(() => {
        //here we create a new Realm "Dog" object as if it was a class
        realm.create('Dog', {name: 'Rex'});
      });
      //here we update state with the data from Realm
      this.setState({ realm });
    });
  }

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

    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          {info}
        </Text>
      </View>
    );
  }
}

and here is a more in depth look at interfacing with Realm storage:

const Realm = require('realm');

// Define your models and their properties
const CarSchema = {
  name: 'Car',
  properties: {
    make:  'string',
    model: 'string',
    miles: {type: 'int', default: 0},
  }
};
const PersonSchema = {
  name: 'Person',
  properties: {
    name:     'string',
    birthday: 'date',
    cars:     'Car[]',
    picture:  'data?' // optional property
  }
};

Realm.open({schema: [CarSchema, PersonSchema]})
  .then(realm => {
    // Create Realm objects and write to local storage
    realm.write(() => {
      const myCar = realm.create('Car', {
        make: 'Honda',
        model: 'Civic',
        miles: 1000,
      });
      myCar.miles += 20; // Update a property value
    });

    // Query Realm for all cars with a high mileage
    const cars = realm.objects('Car').filtered('miles > 1000');

    // Will return a Results object with our 1 car
    cars.length // => 1

    // Add another car
    realm.write(() => {
      const myCar = realm.create('Car', {
        make: 'Ford',
        model: 'Focus',
        miles: 2000,
      });
    });

    // Query results are updated in realtime
    cars.length // => 2
  })
  .catch(error => {
    console.log(error);
  });

It is important to note that Realm is also an Asynchronous storage solution, like the built in AsyncStorage in React Native.

Relationships

  Just like complex database storage solutions using a back-end server, Realm supports complex relationships such as to-one and to-many's. For a to-one relationship, simply set the type of an object's property to the name of the related object, for example from the above code:

const PersonSchema = {
  name: 'Person',
  properties: {
    name:     'string',
    birthday: 'date',
    car:     'Car',
    picture:  'data?' // optional property
  }
};

The car property of the Person object (Person.car) is set to 'Car', or a Car object, declaring the relationship, instead of "string" or "integer" type. For a to-many relationship, simply append a "[]" to the Object Property, defining it as a list. From the example above:

const PersonSchema = {
  name: 'Person',
  properties: {
    name:     'string',
    birthday: 'date',
    cars:     'Car[]',
    picture:  'data?' // optional property
  }
};

Person.cars now return a list of Car objects, because one Person has many cars.

Conclusion

If you are in need of a fast and secure storage solution in a mobile application that handles large sets of data in a locally stored, easy to digest manner, look no further than Realm. The documentation here is extremely helpful, and describes all of the complex actions Realm can handle, including direct queries, advanced relationships, migrations, and encryption.

Posted on by:

spencerlindemuth profile

SpencerLindemuth

@spencerlindemuth

Born to code, live to code better

Discussion

markdown guide
 

No worries, I updated the Realm example from their documentation. You can find the App.js file in this gist. It's the same Dog schema example found in your post.

One more thing, it's considered a professional courtesy to credit the authors when you lift their documentation rather than claim it as your own. Your post is almost a verbatim repost of the Realm doc

 

It would be great if you could update the demo to replace deprecated lifecycle methods like componentWillMount(). Is that method the only way to establish a connection to Realm?

 

"because one Person has many cars"
cries in 0 cars