Realm with Pre Populated Data into Assets

Realm with pre populated data into assets?

Since Realm Java 0.91.0 there has been an assetFile(String) option on the RealmConfiguration that automatically will copy a file from assets and use that if needed (e.g. if the Realm is opened the first time or has been deleted for some reason):

RealmConfiguration config = new RealmConfiguration.Builder()
.assetFile("path/to/file/in/assets") // e.g "default.realm" or "lib/data.realm"
.deleteRealmIfMigrationNeeded()
.build()

The above will copy the file from assets the first time the Realm is opened or if it has been deleted due to migrations (remember to update the asset Realm in that case).


OLD ANSWER:

It is possible to bundle a Realm database in the assets folder, but then you just need to copy it from there when starting the app the first time.

We have an example of how to copy the files here: https://github.com/realm/realm-java/blob/master/examples/migrationExample/src/main/java/io/realm/examples/realmmigrationexample/MigrationExampleActivity.java#L101-Lundefined

copyBundledRealmFile(this.getResources().openRawResource(R.raw.default_realm), "default.realm");

private String copyBundledRealmFile(InputStream inputStream, String outFileName) {
try {
File file = new File(this.getFilesDir(), outFileName);
FileOutputStream outputStream = new FileOutputStream(file);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, bytesRead);
}
outputStream.close();
return file.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

Use pre-populated databases with Realm

Currently there is no way to automatically convert a SQLite database to a Realm database, you would have to manually read all data from the SQLite database and insert them into Realm.

An alternative could be the Realm browser that might make this easier, but it is currently available for MacOS X only. You can read more here: https://github.com/realm/realm-java/issues/435

For the second part: As Realm databases are just a single file so you can easily add a pre-populated realm database to you app and reference it with Realm.getInstance().

Bundle pre-populated realm with react native app

Ok figured this out for android:

1) In the android/app/src/main/assets folder paste the realm.

2) in index.android.js: Use copyBundledRealmFiles() to move them over:

import { AppRegistry } from 'react-native';
import React from 'react';
import Realm from 'realm';
import App from './src/App';

const App2 = () => {
Realm.copyBundledRealmFiles();
return (
<App />
);
};

AppRegistry.registerComponent('SenecaV2', () => App2);

then close all terminals and run react-native run-android to rebundle.

You can check if the realm is being compied over by using the command line to go to (on mac)

library/android/sdk/tools

then the command monitor

this will open up the device monitor. Then, in the device monitor click on file mangager and navgigate to data/data/{packageName}/files and you should see the realm copied over.

If you then want to be able to reference that path in your app use the package:

https://github.com/johanneslumpe/react-native-fs

To give you the path to the files system:

const path = `${RNFS.DocumentDirectoryPath}/{nameOfYourPrePackagedRealmFile}`

You can then use this in the new Realm constructors config path property to access the realm.

https://realm.io/docs/javascript/1.0.0/api/Realm.html#path

Hope this helps anyone with the same problem!

How to pre-populate relational data (e.g. RealmListObject) into Realm

If you want to read in ‘relational data’ you could write an app to read that data, populate your realm objects and save it to realm.

Representing relational data in a flat file usually has some common keys that associate that data. For example people and dogs. The people file may look like this; persons id, name and favorite food

1234,jay,pizza
5678,cindy,steak

then the dogs file would look like this with the dog id, dog name and then the persons (owners) id

1111,rover,1234
2222,spot,1234
3333,scraps,5678

In the above example, jay owns rover and spot and cindy owns scraps.

The realm PersonClass object would be

class PersonClass: Object {
@objc dynamic var person_id = ""
@objc dynamic var person_name = ""
@objc dynamic var fav_food = ""
let dogList = List<DogClass>()
}

and then for the dogs

class DogClass: Object {
@objc dynamic var dog_id = ""
@objc dynamic var dog_name = ""
@objc dynamic var person_id = ""
}

The process would be to read in the people (creating the people objects), read in the dogs, iterate over each dog and add it to that persons dogList - the person could be found by its person_id.

Ideally, it would best to include primary_keys with this structure.

Likewise, you could read all dogs and people into Realm Studio and the add the dogs to their respective people's dogList as well.

You can command-click on filenames to import multiple files into Realm Studio

Pre-populated Realm isn't being copied on the first launch

You have an issue in another place ;)

The first try trowing an exception at first run because you don't have this file yet. And copyItemAtPath not calling after that. So you have an empty default realm file with no data after all of this.

func openRealm() {
let defaultPath = Realm.Configuration.defaultConfiguration.path!
if let v0Path = bundlePath("names.realm") {
if NSFileManager.defaultManager().fileExistsAtPath(defaultPath) {
do {
try NSFileManager.defaultManager().removeItemAtPath(defaultPath)
print("Remove old file")
} catch {
print("Wasn't removed")
}
}
do {
try NSFileManager.defaultManager().copyItemAtPath(v0Path, toPath: defaultPath)
print("Copied.")
} catch {
print("Wasn't copied.")
}
}
}

How to prepopulate Realm database with data?

Finally I came out with the valid workflow for providing repopulated database.

1. Convert your data to json format, as json files can be imported directly using node's npm require method. (I had file in csv format, and wrote python script to convert it into json), so your file should look like this:

{"key0": ["property0", "property1"], "key1": ["property0", "property1"]...}

actually you create json file having schema of your database in mind, example file will map to the following schema:

const MyDBSchema = {
name: 'MyEntity',
primaryKey: 'key',
properties: {
key: 'string',
property0: 'string',
property1: 'int',
property2: 'int',
property3: 'int'
}
};

as you can see, I load properties: property0, property1 from son file, other properties are initialized when I create database.

2. Create you database for the first time:
this includes database generation and selection of place where to put it (be careful on where to put it, as there are limited choices here).

The key element here is that we create database only once, only if there is no database, we use RNFS module for that.

We algorithm is fairly strait forward: if file exists - open it, otherwise create and open it.

export async function openDB() {
realm = await Realm.open({
path: RNFS.DocumentDirectoryPath + '/myDBname.realm',
schema: [MySchema],

});
RNFS.exists(RNFS.DocumentDirectoryPath + '/myDBname.realm').then(exists => {
if(!exists) {
createDB(realm);
}
});
return realm;
}

Database creation is described on the Realm's web page, in any case here is my code snippet for that, so you could see how it maps to the overall picture:

let entities = require('../../data/myJsonFileForDB');
export function createDB(realm){
try {
console.log("Creating DB");
console.log("db path:" + realm.path);
realm.write(() => {
for (let entity in entities) {
let property0 = entities['property0'][0];
let property1 = parseInt(entities['property0'][1]);
realm.create('myEntity',
{
property0: property0,
property1: property1,
property2: 0,
property3: 0,
}, true);
}
});
} catch (error) {
console.log(error)
console.log("Error on creation");
}
};


Related Topics



Leave a reply



Submit