Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use writeCopyTo with react query RealmProvider #6000

Closed
saravanakumargn opened this issue Jul 19, 2023 · 13 comments
Closed

How to use writeCopyTo with react query RealmProvider #6000

saravanakumargn opened this issue Jul 19, 2023 · 13 comments

Comments

@saravanakumargn
Copy link

saravanakumargn commented Jul 19, 2023

How frequently does the bug occur?

Always

Description

How to use writeCopyTo with react query RealmProvider? when I use react query hot i can open Realm and copy from local to sync?

 <AppProvider id={'app-qa-sbapv'}>
        <UserProvider fallback={<AppWelcome />}>
          <RealmProvider schema={schemas}
            sync={{
              flexible                  : true,
              existingRealmFileBehavior : {
                type    : OpenRealmBehaviorType.DownloadBeforeOpen,
                timeOut : 1000,
                timeOutBehavior :
                  // In v11 the enums are not set up correctly, so we need to use the string values
                  OpenRealmTimeOutBehavior?.OpenLocalRealm ?? 'openLocalRealm',
              },
              onError: (_session, error) => {
                console.log('onError: ',error);
              },
            }}
            >
            <App />
</AppProvider>

Stacktrace & log output

No response

Can you reproduce the bug?

Always

Reproduction Steps

No response

Version

@realm/react 0.5.1, "realm": "^11.10.1",

What services are you using?

Atlas Device Sync

Are you using encryption?

No

Platform OS and version(s)

"realm": "^11.10.1",

Build environment

Which debugger for React Native: ..

Cocoapods version

No response

@takameyer
Copy link
Contributor

Hi @saravanakumargn and thanks for reporting. The RealmProvider can't do this. What I would recommend is to initiate this yourself before the RealmProvider is rendered.

Here would be an example of copying a bundled Realm:

// Import a shared configuration that will also be used in your `RealmProvider`
import Realm from "realm";
import {localConfig, syncConfig} from "./myRealmConfig";

export function RealmMigrator(props){
  const user = useUser();
  useEffect( () => {
    // load some sort of logic to determine if you need to do this
    if(!migratedToSync){
	  const originalRealm = await Realm.open(localConfig); 
	  // The `RealmProvider` derives `user` from the `UserProvider`, so we need
      // to add it ourselves here.
	  originalRealm.writeCopyTo({...syncConfig, user});
    }
  }, [user]);
  
  return props.children;
};

Then the wrapper would be:

import {localConfig, syncConfig} from "./myRealmConfig";
import {RealmMigrator} from "./RealmMigrator";

function App(){
  return(
   <AppProvider id={'app-qa-sbapv'}>
        <UserProvider fallback={<AppWelcome />}>
          <RealmMigrator>
	        <RealmProvider {...syncConfig}>
	          <App />
	        </RealmProvider>
          </RealmMigrator>
        </UserProvider>
	</AppProvider>
	);
};

Let us know if this helps!

@saravanakumargn
Copy link
Author

This makes sense @takameyer

But I am getting this error when using originalRealm.writeCopyTo can you tell me what this error means??

writeCopyTo error [Error: Exception in HostFunction: Realm cannot be converted to a flexible sync realm unless flexible sync is already enabled]

export const localConfig: Realm.Configuration = {
  schema : schemas,
  path : 'localOnly.realm',
};

try {
originalRealm.writeCopyTo({
    schema : schemas,
    path   : 'copyLocalToSynced.realm',
    sync   : {
      user                      : app.currentUser,
      flexible                  : true,
    }
  });
} catch (error) {
    console.log('writeCopyTo error ', error)
}

<AppProvider id={'app-qa-sbapv'}>
        <UserProvider fallback={<AppWelcome />}>
          <RealmMigrator>

@takameyer
Copy link
Contributor

@saravanakumargn Have you enabled flexible sync in your Atlas dashboard? Should look something like this:
image

@saravanakumargn
Copy link
Author

saravanakumargn commented Jul 19, 2023

Yes, I did that already and the schema also synced. Pls, check the screenshot Latest Sync Event 10 sec ago. But I am getting this error on writeCopyTo. without this local sync, I am able to save the data and view the collections in the atlas.

Both local and sync modes are working fine separately. I am getting this error on copy originalRealm.writeCopyTo({

import {useEffect} from 'react';

import {useApp, useUser} from '@realm/react';
import Realm from 'realm';

import {localConfig} from './myRealmConfig';

import {schemas} from '@/appCode/db/schemas';

export function RealmMigrator(props){
  const user = useUser();
  const app = useApp();
  useEffect( () => {
    async function checkUser() {
      // load some sort of logic to determine if you need to do this
      const migratedToSync = true;
      if (migratedToSync && app.currentUser){
        const originalRealm = await Realm.open(localConfig);
        try {
          originalRealm.writeCopyTo({
            schema : schemas,
            path   : 'copyLocalToSynced.realm',
            sync   : {
              user     : app.currentUser,
              flexible : true,
            }
          });
        } catch (error) {
          console.log('writeCopyTo error ', error);
        }        
      }
    }
    checkUser();
  }, [app.currentUser, user]);
  
  return props.children;
}

Screenshot 2023-07-19 at 2 59 11 PM

@takameyer
Copy link
Contributor

takameyer commented Jul 19, 2023

@saravanakumargn I apologize, but I believe my example is incorrect:

// Import a shared configuration that will also be used in your `RealmProvider`
import Realm from "realm";
import {localConfig, syncConfig} from "./myRealmConfig";

export function RealmMigrator(props){
  const user = useUser();
  useEffect( () => {
    // load some sort of logic to determine if you need to do this
    if(!migratedToSync){
	  // The `RealmProvider` derives `user` from the `UserProvider`, so we need
      // to add it ourselves here.
	  const syncedRealm = await Realm.open({...syncConfig, user}); 
	  syncedRealm.writeCopyTo(localConfig);
    }
  }, [user]);
  
  return props.children;
};

The writeCopyTo writes the passed in Realm into the open Realm.

@saravanakumargn
Copy link
Author

@takameyer Thanks for looking at this.
I think no issue with your previous code. This should work as per https://www.mongodb.com/docs/realm/sdk/react-native/sync-data/partition-based-sync/#copy-data-and-open-a-new-realm

The use case is anytime I can convert local to sync and sync to local vice-versa. So, the first time when I open the app it's non sync(local). after some time(if premium users i need to copy local to sync and continue the app)

@takameyer
Copy link
Contributor

@saravanakumargn I have reached out to our core team. It appears we don't support the automatic conversion through writeCopyTo at this time (for flexible sync). Sorry for the confusion.

What you could do instead is open the local realm and the sync realm and copy the data directly in your application code, basically doing the conversion yourself. Keep in mind, you must add a flexible sync subscription first and then you can start writing to the synced realm.

This method does offer a deal of flexibility as to what data you want to copy over and possibly update any fields (such as userId). Hope that helps!

@saravanakumargn
Copy link
Author

Thanks for your help & support in this issue @takameyer. Let me check how to do this.

@saravanakumargn
Copy link
Author

As this is expected I am closing this ticket.

@saravanakumargn
Copy link
Author

saravanakumargn commented Aug 3, 2023

@takameyer are you talking about this issue? realm/realm-core#5798
Do you have any idea about this feature roadmap?

@takameyer
Copy link
Contributor

@saravanakumargn That issue was referring to making the error a bit more helpful. The project is on our roadmap for the year, but there's nothing publicly posted at the moment. Sorry I can't provide any further information.

@devsales
Copy link

devsales commented Aug 8, 2023

@saravanakumargn hey, I'm also looking for a consistent way to migrate a local realm to a sync realm. Did you manage to get this working? If you did, do you mind sharing an example code snippet?

My current approach is to send the local data manually to Atlas, then logout the local user and switch to the sync realm, which should download the data from Atlas. So the steps would be:

  1. Export data to Atlas
  2. Register new user with email/pass
  3. Link new user account to the local user account
  4. Logout local user
  5. Login with email and pass
  6. Switch to sync realm

Unfortunately sometimes this does not work (sometimes it does). I guess there is maybe a race-condition between downloading the data and opening the sync realm... not really sure.

@devsales
Copy link

devsales commented Aug 8, 2023

Nevermind, I figured it out :) I just had to skip the exporting of the data to Atlas and instead after switching to the sync realm, open the local Realm and save the local data to the sync realm... and of course close the local Realm afterwards.

  <AppProvider>
    <UserProvider>
      <RealmProvider sync={flexSyncConfig}>
        <App />
      </RealmProvider>
    </UserProvider>
  </AppProvider>

And in <App /> I have a useEffect hook that does something like this:

if (shouldMigrate) {
  const localRealm = await Realm.open(localRealmConfig);
  const arr = localRealm.objects("SomeType");

  realm.write(() => {
    arr.forEach(obj => {
      realm.create("SomeType", obj)
    })
  })
}

As @takameyer mentioned earlier, It's important to call realm.write() after the sync RealmProvider has been initialised with the subscriptions. I hope that helps someone...

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants