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
Masked Input Using Edittext Widget in Android
Android - Build Separate APKs for Different Processor Architectures
Is Deprecated Word the Only Difference Between Fill_Parent and Match_Parent
How to Store and Retrieve a Byte Array (Image Data) to and from a SQLite Database
How to Detect When the Notification/System Bar Is Opened
Android On-Screen Keyboard Auto Popping Up
Android Studio: How to Generate Signed APK Using Gradle
Handlers and Memory Leaks in Android
View Binding - How to Get a Binding for Included Layouts
Transfer Data from One Activity to Another Activity Using Intents
How to Use Sharedpreferences to Save More Than One Values
Notifydatasetchanged Not Working on Recyclerview
Why Is My Field 'Null' After Injection? How to Inject My Object
How to Prevent a Scrollview from Scrolling to a Webview After Data Is Loaded