realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.62k stars 558 forks source link

Support read only realms #392

Closed alazier closed 8 years ago

alazier commented 8 years ago

Needed to support bundled realm files http://stackoverflow.com/questions/36682944/is-there-a-way-to-pre-package-realm-database-default-realm-through-react-nativ

abhaytalreja commented 8 years ago

any updates on this?

alazier commented 8 years ago

This should make it into our next release which should land in the next week or two.

appden commented 8 years ago

@abhaytalreja We just released 0.12.0-rc. You can update to that to give this new feature a try. Thanks!

abhaytalreja commented 7 years ago

@appden Thank you so much for getting this prioritized. I gave it a try and I am still having some difficulty. I have tried 2 different ways to import the Realm DB. I will try to get a sample app ready for you to review. In the mean while is there a sample app, or some documentation that can enable me to do so. My ask is simple i need a pre-populated .realm file that can be editable. I have more than 50K records and would like it to be available when the user installs the app.

appden commented 7 years ago

@abhaytalreja If you need the Realm to be writable, then I suggest you include the prepopulated one in your app bundle, then copy it into the appropriate document storage location when first launched. We don't (yet) provide an API to do this, but I believe you can accomplish this with react-native-fs.

abhaytalreja commented 7 years ago

@appden - you are absolutely right that's how i am doing it, I am using RNFS.movie(sourceAppBundleFile/default.realm, destinationDocumentsFolder/default.realm) - It works, the only problem is, RNFS is a promise based solution, so the new default.realm may take time to be copied, depending on the size. In the mean while, if i am reading any of the info, i get React-native exception. Here is a sample repo. Also, the moment the new default.realm file is available, the app needs a refresh CMD+R - How do we simulate this for the end user? https://github.com/abhaytalreja/realmPrePopulate

P.S. I also tried to create a newDefault.realm file, independent of the default.realm. However, even that file takes time to load for the same above reason. So, i moved the initialization code inside the promise itself. Also, I had to duplicate it, so that it was available for the render function.

Attached is the screenshot of the error, seems more like a React-Native error though. image

[tid:com.facebook.react.RCTBridgeQueue][RCTPerformanceLogger.m:41] Unbalanced calls start/end for tag 12
appden commented 7 years ago

@abhaytalreja Thanks for providing the example code. The issue the approach here is that a new Realm instance is created inside render(). Instead, if the module-level realm instance is not yet created, you can avoid rendering anything that depends on it. Then inside the promise callback where you create the module-level realm instance, you should call this.forceUpdate() to force a re-render.

An alternative would be to store the realm instance inside this.state, and using this.setState() will simplicity cause render() to be called again.

abhaytalreja commented 7 years ago

@appden Thanks, i will try and let you know! appreciate the help!

abhaytalreja commented 7 years ago

@appden - Thanks for the direction, I have updated the repo. It works!

abhaytalreja commented 7 years ago

@appden @alazier - Guys i tried to use this logic and it works in the sample app. However, in my real world React Native app, i have created a realm.js file that exposes utility methods. Just as an example to fetch and update sound preference, see gist. The problem is the Realm file get's copied like a charm and if i do any operations as Scott suggested in the render it worked. However, i get an exception everytime i try to update anything in the database, see the exception gist - Just an FYI... Both the versions of the old Realm as well as the Realm file is 1. Can this be anyhow associated to realm.lock and realm.management folders i am copying? RNFS module is not able to just copy default.realm file. So i have to copy the entire bunch.

I literally tried every work around possible but couldn't get my Realm DB to be updated once i add a new Realm file. This should be straight forward, isn't it? - What am i doing wrong here?

alazier commented 7 years ago

I don't think you should be copying over the management and lock files. Does removing those copies fix anything? I would leave the code to delete the old lock file and management directory.

abhaytalreja commented 7 years ago

@alazier - yes, tried that as well, still having the same issue. :( What i think the problem could be. When I start the app, i initialize the realm in realm.js which acts as an import in my other files. Now, the realm is initialized. The moment i copy and re-intialize the realm. It doens't get used, cause it's using the already loaded version of realm. When i refresh the app CMD+R - The Realm gets reinitialized and everything works (ofcourse refresh means, that in the first run the files were copied). I hope this helps to troubleshoot? If not, i can update the sample app so that you can use it to triage.

Is there anyway to programmatically reinitialize the Realm? just the way it does it if we do CMD+R?

abhaytalreja commented 7 years ago

@alazier - any thoughts?

alazier commented 7 years ago

It sounds like you are trying to copy the file after the Realm is already opened and perhaps we are just overwriting the newly copied Realm? If that is the case you may need to call realm.close() on any opened Realms before deleting the files and copying the new files over.

abhaytalreja commented 7 years ago

@alazier - Tried it... still getting this exception while updating sound.

alazier commented 7 years ago

Hmm this looks like a bug. Are you holding on to references to realm objects from the Realm you are trying to close? Did you register notifications on the Realm you are trying to close?

alazier commented 7 years ago

It looks like we have a but in a recent release caused by causing close when having existing Results objects still alive (what's returned from calling realm.objects). Until we have a fix for this in a future release you might be able to work around this by not calling objects on the Realm you want to close. Not sure if this is possible in your case though.

abhaytalreja commented 7 years ago

Hey There, yes i tried to debug and seems like it was a problem in my code or probably the hierarchy of calls i made. I did play around and was able to get past it. Thank you for all the time and help. realm.close() was really the answer.

abhaytalreja commented 7 years ago

@appden - Thanks for all the help with pre-populated Realm for iOS. Any clue on how to do it with Android? Basically, the way we package the realm file in the main bundle for iOS. I doubt, there is something similar for Android? - Where should i keep the loaded realm file so that RNFS can access it? - I know this is not a bug, but any guidance will be great!

alazier commented 7 years ago

If you put the files in app/src/main/assets then they will be available in the android app. We do this in the test app here: https://github.com/realm/realm-js/tree/master/tests/react-test-app/android/app/src/main

abhaytalreja commented 7 years ago

@alazier Thanks for the response, How do you read the file? I want to use the RNFS.moveFile. Now, what will be the source path? Should it be default.realm, assuming it is already available for android? - The below worked for iOS. I just don't know how to get a handle of the default.realm file from the assets folder.

P.S. - i have copied the default.realm file to assets folder.

RNFS.moveFile(filePathToCopyRealmFrom, filePathToCopyRealm)
            .then((success) => {
              console.log('move was successful');
            })
            .catch((err) => {
              console.log('move was not successful');
              console.log(err);
            });
alazier commented 7 years ago

I'm not sure what path to pass in - we use the android apis directly to copy the files over - https://github.com/realm/realm-js/blob/master/src/android/platform.cpp#L63

If instead of using RNFS you use the copyBundledRealmFiles then all bundled files should get copied to the data directory for you automatically. We do this in the tests here: https://github.com/realm/realm-js/blob/master/tests/js/realm-tests.js#L796

abhaytalreja commented 7 years ago

@alazier Thanks - As it worked like a charm in iOS, i didn't want to do any native code updates for Android too. But, i will certainly try..

Also, copyBundledRealmFiles sounds a good option. That should work. So, i am hoping that if i have the files in the assets folder and i use Realm.copyBundledRealmFiles - That should do the trick. Will update you once i try it.

abhaytalreja commented 7 years ago

@alazier - Okay, so i tried doing Realm.copyBundledRealmFiles - It didn't do anything. I think that is straight forward. P.S. - I have kept the file as default.realm in the assets folder as well as the src/main/res folder.

Also, i did come across a fork for RNFS that has these methods implemented. The only thing is this PR is not yet merged, so not sure how stable it will be.

alazier commented 7 years ago

Did you call it as a function ie Realm.copyBundledRealmFiles();? This should copy all files with the file extension .realm from the assets directory to the data directory. If you share your project maybe I could take a look next week. You can send stuff to us privately at help@realm.io

abhaytalreja commented 7 years ago

Yes, Sir - ofcourse it was a function 🎯 :) Realm.copyBundledRealmFiles(); - I have updated the sample repo. You can use any Realm file and try. Once again, thanks for your time!

alazier commented 7 years ago

So it doesn't look like there is an assets folder with realm files in the repo. Should be here - https://github.com/abhaytalreja/realmPrePopulate/tree/master/android/app/src/main

abhaytalreja commented 7 years ago

@alazier - apologies, i just edited the piece of code in the repo. However, when i tried to create a new repo, i got the exception as mentioned in the new issue i logged. I am not able to proceed cause of that error.

alazier commented 7 years ago

Were you able to resolve this? Did you try this https://github.com/realm/realm-js/issues/527#issuecomment-233117177 ?

abhaytalreja commented 7 years ago

Yup! i did... and i was successful in creating the package! Thank you so much guys! special thanks to you and your team!

abhaytalreja commented 7 years ago

@alazier - I think the vanilla project works, however, seems like Android has a limitation on the file size that can be copied from the assets, it is 500 kb and i am trying to move a file that is 2.4 mb (compressed). I will have to figure out an alternative i guess.

alazier commented 7 years ago

@abhaytalreja - you could try to download the realm file from a server when the app launches. Not sure if that would work for your applications. Or perhaps is possible to store a bundled realm file somewhere else?

abhaytalreja commented 7 years ago

@alazier - Well, I need data to be available on start... and you have a great idea. I can try to have it loaded somewhere and then use RNFS to download it. I will let you know, how it goes. Thank you!

I just tried with a smaller file, like 492 Kb, it works. If not, i will go with this option and restrict the data i am bundling for Android.

abhaytalreja commented 7 years ago

@alazier - 1 weird thing happened, if i keep another file temp.default in the raw folder (same realm file) and then have default.realm in the assets folder. It gets loaded correctly and completely. So, once the new file is loaded, all i need to do is use the right path option! not sure why it is working, but it's getting the job done!

I think i should be set... well, i may revisit for Windows app :)

stefanwuest commented 7 years ago

Hey, @abhaytalreja did you get this to work (particularly with Android)? Would love to hear about your solution on this. I tried Realm.copyBundledRealmFiles(); but nothing happened on the file system (Checked with Android Device Monitor)

mintproduct commented 7 years ago

Hi, @appden , I've found that you had resolved this problem in 0.12.0-rc. However I still can't find a proper way to use this readOnly feature in React Native. Could you give me some instruction?

alazier commented 7 years ago

@mintproduct you set the readOnly flag to true when opening a realm:

var realm = new Realm({ schema: [...], readOnly: true });

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

cwagner22 commented 6 years ago

Is it possible to open a readOnly realm database on Android without having to copy it to the Document folders? I created a separate issue #1047 because it doesn't seem to be possible.

MatheusParanhos commented 5 years ago

Hey guys, I'm having some trouble with this.. I did as this guy made here: https://www.youtube.com/watch?v=nS6YCq2OdeA, unfortunately without any results.. it looks like whenever I update the file on the source, the changes don't get reflected on my bundled files.. I will try the Realm.copyBundledRealmFiles() and will come here with an update.. but so far I'm struggling with this one...

nirinchev commented 5 years ago

Please avoid commenting on issues that have been closed for years with tangentially related problems as it's very likely these will get overlooked. Instead, it's much better to open a new issue with information specific to your problem.