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

DataStore unable to work. #4535

Closed
ykbryan opened this issue Dec 9, 2019 · 31 comments
Closed

DataStore unable to work. #4535

ykbryan opened this issue Dec 9, 2019 · 31 comments
Labels
to-be-reproduced Used in order for Amplify to reproduce said issue

Comments

@ykbryan
Copy link

ykbryan commented Dec 9, 2019

Describe the bug
Unable to get DataStore save data.

To Reproduce
Steps to reproduce the behavior:

  1. create a new reactjs app create-react-app newapp
  2. add amplify and graphql api with the following schema
enum PostStatus {
  ACTIVE
  INACTIVE
}

type Post @model {
  id: ID!
  title: String!
  rating: Int!
  status: PostStatus!
}
  1. run amplify codegen models
  2. run amplify push and wait for it to finish
  3. refer to the create datastore in the documentation and create a function onCreatePost
  4. run yarn start
  5. see the reactjs page, open chrome console. wait for the waiting
[WARN] 44:02.180 DataStore - Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type FieldUndefined: Field '_lastChangedAt' in type 'Post' is undefined @ 'onCreatePost/_lastChangedAt'"},{"message":"Validation error of type FieldUndefined: Field '_version' in type 'Post' is undefined @ 'onCreatePost/_version'"},{"message":"Validation error of type FieldUndefined: Field '_deleted' in type 'Post' is undefined @ 'onCreatePost/_deleted'"},{"message":"Validation error of type FieldUndefined: Field '_version' in type 'Post' is undefined @ 'onCreatePost/_version'"},{"message":"Validation error of type FieldUndefined: Field '_lastChangedAt' in type 'Post' is undefined @ 'onCreatePost/_lastChangedAt'"},{"message":"Validation error of type FieldUndefined: Field '_deleted' in type 'Post' is undefined @ 'onCreatePost/_deleted'"}]}

and the error:

Uncaught TypeError: Cannot read property 'observer' of undefined
    at AWSAppSyncRealTimeProvider._timeoutStartSubscriptionAck (AWSAppSyncRealTimeProvider.ts:506)
    at AWSAppSyncRealTimeProvider.ts:318

Expected behavior
DataStore and new Post should be created.

Screenshots
If applicable, add screenshots to help explain your problem.

Screenshot 2019-12-09 21 32 19
Screenshot 2019-12-09 21 35 24

Environment
npx envinfo --system --binaries --browsers --npmPackages --npmGlobalPackages
npx: installed 1 in 1.428s

  System:
    OS: macOS Mojave 10.14.6
    CPU: (8) x64 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
    Memory: 167.82 MB / 16.00 GB
    Shell: 5.3 - /bin/zsh
  Binaries:
    Node: 8.16.0 - ~/.nvm/versions/node/v8.16.0/bin/node
    Yarn: 1.19.2 - /usr/local/bin/yarn
    npm: 6.13.2 - ~/.nvm/versions/node/v8.16.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Browsers:
    Chrome: 78.0.3904.108
    Firefox: 68.3.0
    Safari: 13.0.3
  npmPackages:
    @aws-amplify/core: ^2.2.0 => 2.2.0 
    @aws-amplify/datastore: ^1.0.2 => 1.0.2 
    @testing-library/jest-dom: ^4.2.4 => 4.2.4 
    @testing-library/react: ^9.3.2 => 9.3.2 
    @testing-library/user-event: ^7.1.2 => 7.1.2 
    react: ^16.12.0 => 16.12.0 
    react-dom: ^16.12.0 => 16.12.0 
    react-scripts: 3.3.0 => 3.3.0 
  npmGlobalPackages:
    @aws-amplify/cli: 4.5.0
    aws-cdk: 1.18.0
    create-react-app: 3.3.0
    create-react-native-app: 2.0.2
    eslint-config-airbnb: 18.0.1
    expo-cli: 3.9.1
    expo: 35.0.1
    firebase-tools: 7.9.0
    gatsby-cli: 2.8.16
    jsforce: 1.9.3
    mocha: 6.2.2
    npm: 6.13.2
    react-devtools: 4.2.1
    react-native-git-upgrade: 0.2.7
    react-native-rename: 2.4.1
    react-native: 0.61.2
    serve: 11.2.0
    serverless: 1.59.1

Smartphone (please complete the following information):

  • Device: MacBook Pro (15-inch, 2017)
  • OS: macOS Mojave 10.14.6
  • Browser Chrome
  • Version 78.0.3904.108

Additional context

Sample code

You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app.

@ykbryan ykbryan added the to-be-reproduced Used in order for Amplify to reproduce said issue label Dec 9, 2019
@undefobj
Copy link
Contributor

undefobj commented Dec 9, 2019

Do you have an aws-exports.js file in your project?

@ykbryan
Copy link
Author

ykbryan commented Dec 9, 2019

Do you have an aws-exports.js file in your project?

Yes. It includes aws_project_region, aws_appsync_graphqlEndpoint, aws_appsync_region, aws_appsync_authenticationType and aws_appsync_apiKey

@undefobj
Copy link
Contributor

undefobj commented Dec 9, 2019

For your step #2 above:

add amplify and graphql api with the following schema

How did you do this? Was it with npx amplify-app?

@ykbryan
Copy link
Author

ykbryan commented Dec 9, 2019

For your step #2 above:

add amplify and graphql api with the following schema

How did you do this? Was it with npx amplify-app?

i tried both npx amplify-app and amplify add api and do the codegen models later on.

@undefobj
Copy link
Contributor

undefobj commented Dec 9, 2019

It sounds like you don't have a syncable API setup. Can you do the following:

  • Create react app
  • Inside that directory run npx amplify-app with the schema above
  • npm run amplify-modelgen inside that directory
  • npm i @aws-amplify/core @aws-amplify/datastore
  • npm run amplify-push
  • Run your app code

@ykbryan
Copy link
Author

ykbryan commented Dec 9, 2019

It sounds like you don't have a syncable API setup. Can you do the following:

  • Create react app
  • Inside that directory run npx amplify-app with the schema above
  • npm run amplify-modelgen inside that directory
  • npm i @aws-amplify/core @aws-amplify/datastore
  • npm run amplify-push
  • Run your app code

Ok, now i got no error from here but the new Post still does not appear in the dynamoDB.

Screenshot 2019-12-10 01 39 54

Here's the source code for testing


import React, { useEffect } from 'react';
import logo from './logo.svg';
import './App.css';

import Amplify from '@aws-amplify/core';
import { DataStore, Predicates } from '@aws-amplify/datastore';
import { Post, PostStatus } from './models';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

function App() {
  async function onCreatePost() {
    const result = await DataStore.save(
      new Post({
        title: `My First Post`,
        rating: 10,
        status: PostStatus.ACTIVE
      })
    );
    console.log(result);
  }

  onCreatePost();

  useEffect(() => {
    const subscription = DataStore.observe(Post).subscribe(msg => {
      console.log(msg.model, msg.opType, msg.element);
    });

    return () => {
      subscription.unsubscribe();
    };
  });

  return (
    <div className='App'>
      <header className='App-header'>
        <img src={logo} className='App-logo' alt='logo' />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className='App-link'
          href='https://reactjs.org'
          target='_blank'
          rel='noopener noreferrer'
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

@ykbryan
Copy link
Author

ykbryan commented Dec 9, 2019

Ok, i got it to work after I move the trigger to onClick={onCreatePost} instead of calling the method in the App() directly.

Here's the source code for testing


import React, { useEffect } from 'react';
import logo from './logo.svg';
import './App.css';

import Amplify from '@aws-amplify/core';
import { DataStore, Predicates } from '@aws-amplify/datastore';
import { Post, PostStatus } from './models';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

function App() {
  async function onCreatePost() {
    const result = await DataStore.save(
      new Post({
        title: `My First Post`,
        rating: 10,
        status: PostStatus.ACTIVE
      })
    );
    console.log(result);
  }

  useEffect(() => {
    const subscription = DataStore.observe(Post).subscribe(msg => {
      console.log(msg.model, msg.opType, msg.element);
    });

    return () => {
      subscription.unsubscribe();
    };
  });

  return (
    <div className='App'>
      <header className='App-header'>
        <img src={logo} className='App-logo' alt='logo' />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className='App-link'
          href='https://reactjs.org'
          target='_blank'
          rel='noopener noreferrer'
        >
          Learn React
          <input type='button' value='NEW' onClick={onCreatePost} />
        </a>
      </header>
    </div>
  );
}

export default App;

@ykbryan ykbryan closed this as completed Dec 9, 2019
@undefobj
Copy link
Contributor

undefobj commented Dec 9, 2019

@ykbryan great to hear! Is there anything in the docs that we could improve that would've made this easier for you?

@ykbryan
Copy link
Author

ykbryan commented Dec 9, 2019

@ykbryan great to hear! Is there anything in the docs that we could improve that would've made this easier for you?

@undefobj Can you maybe add/share how will I know if i have setup my syncable API correctly and how to test it locally as well?

@undefobj
Copy link
Contributor

undefobj commented Dec 9, 2019

Thanks @ykbryan I've added this as a backlog item in the CLI repo

@kevinold
Copy link

kevinold commented Dec 14, 2019

I ran into this issue when adding DataStore to an existing API.

Ultimately I needed to run amplify update api and follow the prompts to update the conflict resolution strategies (https://aws-amplify.github.io/docs/js/datastore#conflict-resolution) so that the API had this support and my mutations were updated to have these fields:

_version
_deleted
_lastChangedAt

@rakannimer
Copy link

Hey @kevinold

I'm getting the same error here, missing _version _deleted and _lastChangedAt.

What did you set the conflict resolution to to fix it ?

@kevinold
Copy link

@rakannimer I selected optimistic concurrency per the conflict resolution docs on the DataStore page. Do that and run amplify push and it will update your mutations to include those fields.

I will also add the note here that I've filed an issue with being able fully use the DataStore after upgrading the API. That issue is being tracked here: #4588

@rakannimer
Copy link

Thanks for the reply !

It did not work for my case, I'll try to setup a simple repro and maybe open another issue, or I'll stick to using vanilla GraphQL.

@pubkey
Copy link

pubkey commented Dec 26, 2019

@kevinold thanks, this worked in my case

@simalexan
Copy link

simalexan commented Dec 27, 2019

@undefobj I think the point missed for the case of @ykbryan was that, since this is a functional React component, it should mention that invoking DataStore should be either within a useEffect hook or as an event handler function, as the component needs to mount.

The React component lifecycle should be respected.

@simontegg
Copy link

simontegg commented Dec 28, 2019

Running update and adding conflict resolution did not work in may case. _version was added but not _lastChangedAt or _deleted

@phishy
Copy link

phishy commented Jan 6, 2020

DataStore.save does not like to save the first record.

For me, this saves 1 record:

window.LOG_LEVEL = "DEBUG";

async function main() {
  await DataStore.save(
    new Session({
      user: `Hello`
    })
  );
  await DataStore.save(
    new Session({
      user: `Hola`
    })
  );
}

main();

@apoorvmote
Copy link

I selected optimistic concurrency per the conflict resolution docs on the DataStore page. Do that and run amplify push and it will update your mutations to include those fields.

@kevinold your advice/trick did work for my fresh/new project. I can't believe they didn't mention this issue in documentation with the trick. Thank god I found this page.

But it also created 2 different tables in Dynamodb(cloud) for same Todo type. Following are names for both tables

  1. Todo-xxxxx
  2. Amplify-Datastore-xxxxx

And every data from Todo table is replicated into the Amplify-Datastore table.
I don't understand datastore much. To me it works on witchcraft magic.
Is data replication an expected behaviour?

@chufgard
Copy link

I ran into this issue when adding DataStore to an existing API.

Ultimately I needed to run amplify update api and follow the prompts to update the conflict resolution strategies (https://aws-amplify.github.io/docs/js/datastore#conflict-resolution) so that the API had this support and my mutations were updated to have these fields:

_version
_deleted
_lastChangedAt

You could also add this you the transform.conf.json directly:
{ "Version": 5, "ResolverConfig": { "project": { "ConflictHandler": "AUTOMERGE", "ConflictDetection": "VERSION" } } }

This information must be included to the documentation! It's pretty hard to guess... Or "@versioned" should generate it.

@cnwork
Copy link

cnwork commented Apr 6, 2020

DataStore.save does not like to save the first record.

For me, this saves 1 record:

window.LOG_LEVEL = "DEBUG";

async function main() {
  await DataStore.save(
    new Session({
      user: `Hello`
    })
  );
  await DataStore.save(
    new Session({
      user: `Hola`
    })
  );
}

main();

Same thing for me in a Quasar project. I have a form that triggers a Datastore.save() and the first entry gets saved locally but not in the DynamoDB. From second on onwards they all get saved properly. Why is the first one not being synced to the backend?

@undefobj
Copy link
Contributor

undefobj commented Apr 6, 2020

DataStore.save does not like to save the first record.

For me, this saves 1 record:

window.LOG_LEVEL = "DEBUG";

async function main() {
  await DataStore.save(
    new Session({
      user: `Hello`
    })
  );
  await DataStore.save(
    new Session({
      user: `Hola`
    })
  );
}

main();

Same thing for me in a Quasar project. I have a form that triggers a Datastore.save() and the first entry gets saved locally but not in the DynamoDB. From second on onwards they all get saved properly. Why is the first one not being synced to the backend?

@cnwork could you open up a new issue with all the details of your project setup

@cnwork
Copy link

cnwork commented Apr 7, 2020

@cnwork could you open up a new issue with all the details of your project setup

@undefobj sure, what kind of details are needed?

@ryanweaver718
Copy link

ryanweaver718 commented Apr 30, 2020

@cnwork @undefobj @ykbryan I also am having the same issue as you are and I put the function call in an onClick handler as well but still am getting the issue of the first record not being saved an all future ones being saved.
Was there nothing else you did to get it to work? Has there been any resolution to this?

@blydewright
Copy link

blydewright commented May 2, 2020

Hi :) I'm experiencing the same issue of the first object not being synced upon a DataStore.save(). Subsequent DataStore.save()'s correctly sync. Both first and subsequent objects are correctly saved to local storage (in this case, my browser's indexedDb).

I am executing these saves within a click handler. This happens in both mock environment, and cloud using the auto-generated schema (Blog, Post, Comment) from amplify api add using authentication as API key.

It seems like the first save() method does some kind of initialization without synchronizing that object, but allows subsequent saves to work correctly. When additional saves are made in other handlers, they work correctly. So it's the first save after initializing.

Let me know if more info is needed.

@mdegrees
Copy link

Fixed the issue with:
. Amplify update API
. Enable Datastore for the whole API

@ykbryan
Copy link
Author

ykbryan commented May 22, 2020

@cnwork @undefobj @ykbryan I also am having the same issue as you are and I put the function call in an onClick handler as well but still am getting the issue of the first record not being saved an all future ones being saved.
Was there nothing else you did to get it to work? Has there been any resolution to this?

Do you have a link to your repo/source code that does this?

@IsaacTrevino
Copy link

I ran into this issue when adding DataStore to an existing API.
Ultimately I needed to run amplify update api and follow the prompts to update the conflict resolution strategies (https://aws-amplify.github.io/docs/js/datastore#conflict-resolution) so that the API had this support and my mutations were updated to have these fields:

_version
_deleted
_lastChangedAt

You could also add this you the transform.conf.json directly:
{ "Version": 5, "ResolverConfig": { "project": { "ConflictHandler": "AUTOMERGE", "ConflictDetection": "VERSION" } } }

This information must be included to the documentation! It's pretty hard to guess... Or "@versioned" should generate it.

So once I updated via amplify-cli amplify update api , then enable DataStore for entire GraphQL ,
I had to remove my items from the dynamo db table and reinsert them via DataStore instead of GraphQL, the Fields were now included and ready to roll. Thanks

@solisarg
Copy link

Just a warning: don't forget to update your models when adding the Datastore, otherwise you get errors saying that version doesn't exist (because your models need to be updated)

I skip the model update so get the error, need to run again amplify update API to take care of my models, below an example from the todolist example

datastore

You select interactively which models to update (all of them), then your schema.graphql (if you use graphql) will have all the necessary to run flawlessly

And as IssacTrvino mention: think in advance if you will use DataStore, because if you add later, you need to clean the table and reinsert all of the items again

@abhimanusharma
Copy link

It sounds like you don't have a syncable API setup. Can you do the following:

  • Create react app
  • Inside that directory run npx amplify-app with the schema above
  • npm run amplify-modelgen inside that directory
  • npm i @aws-amplify/core @aws-amplify/datastore
  • npm run amplify-push
  • Run your app code

I am using yarn. any suggestions.

@github-actions
Copy link

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 18, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
to-be-reproduced Used in order for Amplify to reproduce said issue
Projects
None yet
Development

No branches or pull requests