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 update does not increment version correctly after second update #9942

Closed
3 tasks done
djcade32 opened this issue May 27, 2022 · 7 comments
Closed
3 tasks done
Assignees
Labels
DataStore Related to DataStore category documentation Related to documentation feature requests

Comments

@djcade32
Copy link

djcade32 commented May 27, 2022

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Authentication, DataStore

Amplify Categories

Environment information

System:
    OS: Windows 10 10.0.19044
    CPU: (6) x64 AMD Ryzen 5 3600 6-Core Processor
    Memory: 8.50 GB / 15.95 GB
  Binaries:
    Node: 16.13.2 - C:\Program Files\nodejs\node.EXE
    npm: 8.5.2 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromium (101.0.1210.53)
    Internet Explorer: 11.0.19041.1566
  npmPackages:
    @babel/core: ^7.12.9 => 7.18.2
    @react-native-async-storage/async-storage: ^1.17.5 => 1.17.5
    @react-native-community/netinfo: ^8.3.0 => 8.3.0
    @react-native-picker/picker: ^2.4.1 => 2.4.1
    HelloWorld:  0.0.1
    aws-amplify: ^4.3.24 => 4.3.24
    aws-amplify-react-native: ^6.0.4 => 6.0.4
    expo: ~45.0.0 => 45.0.4
    expo-status-bar: ~1.3.0 => 1.3.0
    hermes-inspector-msggen:  1.0.0
    react: 17.0.2 => 17.0.2
    react-dom: 17.0.2 => 17.0.2
    react-native: 0.68.2 => 0.68.2
    react-native-web: 0.17.7 => 0.17.7
  npmGlobalPackages:
    @angular/cli: 12.2.8
    @aws-amplify/cli: 8.0.2
    @vue/cli: 4.5.11
    create-react-app: 5.0.0
    create-react-native-app: 3.8.0
    expo-cli: 5.4.6
    jake: 10.8.2
    nodemon: 2.0.12
    npm: 8.5.2


Describe the bug

I am new to using Amplify. So I am hoping this is an easy fix. I am having problems with updating the Aws-Amplify database. This is my schema.graphql

type User @model @auth(rules: [{ allow: public }]) {
  id: ID!
  name: String!
  age: String!
  sub: String!
}

I can save a User to the database just fine but when I try to update that same user more than twice, datastore does not perform the update.

I did some further digging by observing the User model and found out that datastore is incrementing the version with the updated values correctly for the first update. But when I try to attempt a second update it decreases the version for the new User value but then increments it again with the previous value. So it looks like the database never got updated. I created console log outputs to show the process. I provided the logs below hopefully this helps illustrate the problem. I am changing and updating the age field.

Logged In User User {
  "_deleted": null,
  "_lastChangedAt": 1653609053896,
  "_version": 195,
  "age": "45",
  "createdAt": "2022-05-26T21:22:40.376Z",
  "id": "fdb49927-5083-475e-b20c-d0bacf07ca34",
  "name": "Norman",
  "sub": "6cf85f4f-8ac5-45d3-a63e-e451ceba763a",
  "updatedAt": "2022-05-26T23:50:19.614Z",
}

** First attempt to Update **
Observing  User {
  "_deleted": null,
  "_lastChangedAt": 1653609053896,
  "_version": 195,
  "age": "30",
  "createdAt": "2022-05-26T21:22:40.376Z",
  "id": "fdb49927-5083-475e-b20c-d0bacf07ca34",
  "name": "Norman",
  "sub": "6cf85f4f-8ac5-45d3-a63e-e451ceba763a",
  "updatedAt": "2022-05-26T23:50:19.614Z",
}

Observing  User {
  "_deleted": null,
  "_lastChangedAt": 1653610531206,
  "_version": 196,
  "age": "30",
  "createdAt": "2022-05-26T21:22:40.376Z",
  "id": "fdb49927-5083-475e-b20c-d0bacf07ca34",
  "name": "Norman",
  "sub": "6cf85f4f-8ac5-45d3-a63e-e451ceba763a",
  "updatedAt": "2022-05-27T00:15:31.158Z",
}

Observing  User {
  "_deleted": null,
  "_lastChangedAt": 1653610531206,
  "_version": 196,
  "age": "30",
  "createdAt": "2022-05-26T21:22:40.376Z",
  "id": "fdb49927-5083-475e-b20c-d0bacf07ca34",
  "name": "Norman",
  "sub": "6cf85f4f-8ac5-45d3-a63e-e451ceba763a",
  "updatedAt": "2022-05-27T00:15:31.158Z",
}

** Second attempt to update **
Observing  User {
  "_deleted": null,
  "_lastChangedAt": 1653609053896,
  "_version": 195,
  "age": "10",
  "createdAt": "2022-05-26T21:22:40.376Z",     
  "id": "fdb49927-5083-475e-b20c-d0bacf07ca34",
  "name": "Norman",
  "sub": "6cf85f4f-8ac5-45d3-a63e-e451ceba763a",
  "updatedAt": "2022-05-26T23:50:19.614Z",
}

Observing  User {
  "_deleted": null,
  "_lastChangedAt": 1653610557383,
  "_version": 197,
  "age": "30",
  "createdAt": "2022-05-26T21:22:40.376Z",
  "id": "fdb49927-5083-475e-b20c-d0bacf07ca34",
  "name": "Norman",
  "sub": "6cf85f4f-8ac5-45d3-a63e-e451ceba763a",
  "updatedAt": "2022-05-27T00:15:31.158Z",
}

Observing  User {
  "_deleted": null,
  "_lastChangedAt": 1653610557383,
  "_version": 197,
  "age": "30",
  "createdAt": "2022-05-26T21:22:40.376Z",
  "id": "fdb49927-5083-475e-b20c-d0bacf07ca34",
  "name": "Norman",
  "sub": "6cf85f4f-8ac5-45d3-a63e-e451ceba763a",
  "updatedAt": "2022-05-27T00:15:31.158Z",
}

Expected behavior

I expect the database to update and show the correct value. I expect the versions to increment correctly when using the datastore.

Reproduction steps

  1. Create a new react native app
  2. Install all necessary dependencies provided in the AWS-amplify get started guide for react-native expo apps.
  3. Create an AWS-amplify database online using the Amplify Studio.
  4. Set up Authentication.
  5. Create a simple User data model with name, age, and sub fields. All fields should be a required string.
    Capture
  6. Deploy database and pull data into react native app.
  7. The code I used to update the database is below

Code Snippet

// Put your code below this line.
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, TextInput, Button } from "react-native";
import { useState, useEffect } from "react";
import { Amplify, Analytics } from "aws-amplify";
import awsconfig from "./src/aws-exports";
import { withAuthenticator } from "aws-amplify-react-native";
import { Auth, DataStore } from "aws-amplify";
import { User } from "./src/models";

Amplify.configure({ ...awsconfig, Analytics: { disabled: true } });

function App() {
  const [authUser, setAuthUser] = useState(null);
  const [dbUser, setDbUser] = useState(null);
  const [submitted, setSubmitted] = useState(false);
  const sub = authUser?.attributes?.sub;

  const [name, setName] = useState("");
  const [age, setAge] = useState("");

  useEffect(() => {
    Auth.currentAuthenticatedUser({ bypassCache: true }).then(setAuthUser);
  }, []);

  useEffect(() => {
    DataStore.query(User, (user) => user.sub("eq", sub)).then((users) => {
      console.log("Logged In User", users[0]);
      setDbUser(users[0]);
    });
  }, [sub]);

  async function createUser() {
    try {
      const user = await DataStore.save(
        new User({
          name,
          age,
          sub,
        })
      );
      console.log("Created User ", user);
      setDbUser(user);
    } catch (e) {
      console.log("Error creating user:");
      console.log(e);
    }
  }

  async function updateUser() {
    try {
      await DataStore.save(
        User.copyOf(dbUser, (updated) => {
          updated.name = name;
          updated.age = age;
        })
      ).then(setDbUser);
    } catch (e) {
      console.log(e);
    }
  }

  useEffect(() => {
    const subscription = DataStore.observe(User).subscribe(
      ({ msg, element }) => {
        console.log("Observing ", element);
      }
    );
    return () => subscription.unsubscribe();
  }, [dbUser]);

  return (
    <View style={styles.container}>
      {dbUser ? (
        <>
          <Text>Name</Text>
          <TextInput
            onChangeText={(value) => setName(value)}
            placeholder="Name"
          ></TextInput>

          <Text style={{ marginTop: 20 }}>age</Text>
          <TextInput
            style={{ marginBottom: 20 }}
            onChangeText={(value) => setAge(value)}
            placeholder="Age"
          ></TextInput>
          <Button onPress={updateUser} title="UPDATE" />
        </>
      ) : (
        <>
          <Text>Name</Text>
          <TextInput
            onChangeText={(value) => setName(value)}
            placeholder="Name"
          ></TextInput>

          <Text style={{ marginTop: 20 }}>age</Text>
          <TextInput
            style={{ marginBottom: 20 }}
            onChangeText={(value) => setAge(value)}
            placeholder="Age"
          ></TextInput>
          <Button onPress={createUser} title="SUBMIT" />
        </>
      )}
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});

export default withAuthenticator(App);

Log output

When I turn on debug, this is what I get.

[DEBUG] 46:21.702 DataStore - Attempting mutation with authMode: API_KEY
[DEBUG] 46:21.704 Util -  attempt #1 with this vars: ["User","Update","{\"age\":\"32\",\"id\":\"fdb49927-5083-475e-b20c-d0bacf07ca34\",\"_version\":197,\"_lastChangedAt\":1653610557383,\"_deleted\":null}","{}",null,null,{"data":"{\"age\":\"32\",\"id\":\"fdb49927-5083-475e-b20c-d0bacf07ca34\",\"_version\":197,\"_lastChangedAt\":1653610557383,\"_deleted\":null}","modelId":"fdb49927-5083-475e-b20c-d0bacf07ca34","model":"User","operation":"Update","condition":"{}","id":"01G41DVPXZ4WMJ40V1SKYNQK10"}] 
[DEBUG] 46:21.709 RestClient - POST https://2baa7tul5rdqzcfwtjxou4ngma.appsync-api.us-east-1.amazonaws.com/graphql
[DEBUG] 46:22.60 DataStore - Mutation sent successfully with authMode: API_KEY
[DEBUG] 46:22.214 AWSAppSyncRealTimeProvider - subscription message from AWS AppSync RealTime: {"id":"828f2d8f-b937-49ea-b6ea-be9f53eec794","type":"data","payload":{"data":{"onUpdateUser":{"id":"fdb49927-5083-475e-b20c-d0bacf07ca34","name":"Norman","age":"32","sub":"6cf85f4f-8ac5-45d3-a63e-e451ceba763a","createdAt":"2022-05-26T21:22:40.376Z","updatedAt":"2022-05-27T00:46:21.886Z","_version":198,"_lastChangedAt":1653612381962,"_deleted":null}}}}
[DEBUG] 46:22.216 AWSAppSyncRealTimeProvider Object {
  "id": "828f2d8f-b937-49ea-b6ea-be9f53eec794",      
  "observer": SubscriptionObserver {
    "_subscription": Subscription {
      "_cleanup": [Function anonymous],
      "_observer": Object {
        "error": [Function error],
        "next": [Function next],
        "start": [Function error],
      },
      "_queue": undefined,
      "_state": "ready",
    },
  },
  "query": "subscription operation {
  onUpdateUser {
    id
    name
    age
    sub
    createdAt
    updatedAt
    _version
    _lastChangedAt
    _deleted
  }
}
",
  "variables": Object {},
}
[DEBUG] 47:00.808 DataStore - Attempting mutation with authMode: API_KEY
[DEBUG] 47:00.809 Util -  attempt #1 with this vars: ["User","Update","{\"age\":\"50\",\"id\":\"fdb49927-5083-475e-b20c-d0bacf07ca34\",\"_version\":197,\"_lastChangedAt\":1653610557383,\"_deleted\":null}","{}",null,null,{"data":"{\"age\":\"50\",\"id\":\"fdb49927-5083-475e-b20c-d0bacf07ca34\",\"_version\":197,\"_lastChangedAt\":1653610557383,\"_deleted\":null}","modelId":"fdb49927-5083-475e-b20c-d0bacf07ca34","model":"User","operation":"Update","condition":"{}","id":"01G41DVPXZ4WMJ40V1SKYNQK11"}] 
[DEBUG] 47:00.811 RestClient - POST https://2baa7tul5rdqzcfwtjxou4ngma.appsync-api.us-east-1.amazonaws.com/graphql
[DEBUG] 47:00.991 DataStore - Mutation sent successfully with authMode: API_KEY
[DEBUG] 47:01.130 AWSAppSyncRealTimeProvider - subscription message from AWS AppSync RealTime: {"id":"828f2d8f-b937-49ea-b6ea-be9f53eec794","type":"data","payload":{"data":{"onUpdateUser":{"id":"fdb49927-5083-475e-b20c-d0bacf07ca34","name":"Norman","age":"32","sub":"6cf85f4f-8ac5-45d3-a63e-e451ceba763a","createdAt":"2022-05-26T21:22:40.376Z","updatedAt":"2022-05-27T00:46:21.886Z","_version":199,"_lastChangedAt":1653612420947,"_deleted":null}}}}
[DEBUG] 47:01.132 AWSAppSyncRealTimeProvider Object {
  "id": "828f2d8f-b937-49ea-b6ea-be9f53eec794",      
  "observer": SubscriptionObserver {
    "_subscription": Subscription {
      "_cleanup": [Function anonymous],
      "_observer": Object {
        "error": [Function error],
        "next": [Function next],
        "start": [Function error],
      },
      "_queue": undefined,
      "_state": "ready",
    },
  },
  "query": "subscription operation {
  onUpdateUser {
    id
    name
    age
    sub
    createdAt
    updatedAt
    _version
    _lastChangedAt
    _deleted
  }
}
",
  "variables": Object {},
}
[DEBUG] 47:04.361 AWSAppSyncRealTimeProvider - subscription message from AWS AppSync RealTime: {"type":"ka"}
[DEBUG] 47:04.364 AWSAppSyncRealTimeProvider Object {
  "id": "",
  "observer": null,
  "query": "",
  "variables": Object {},
}


aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

@jedgrant
Copy link

I have the same issue and assumed I didn't know what I was doing. To get updates to work I had to requery the record, even if it already had it in state, then mutate that freshly queried data to save. Still very interested in the solve for this generally. All I should need to send is the ID and the updated value and it should work.
aws-amplify/docs#4336

@chrisbonifacio chrisbonifacio added DataStore Related to DataStore category pending-triage Issue is pending triage labels May 31, 2022
@djcade32
Copy link
Author

@jedgrant Yes, I eventually came across this workaround too. I ended up fetching and saving the data again within datastore.observe.
I agree I feel like there has to be a better way of updating data.

@undefobj
Copy link
Contributor

undefobj commented Jun 1, 2022

@jedgrant @djcade32 are you both also doing text input for your React UI? You shouldn't need to ever re-query for the latest version, this should happen automatically by DataStore as you can see in this example: https://docs.amplify.aws/lib/datastore/examples/q/platform/js/#example-application

I have a suspicion that this may be due to text input and/debouncing of some sort that we might need to document better but I'm trying to understand the why on this happening first. Also @jedgrant are you using React Native as well?

@jedgrant
Copy link

jedgrant commented Jun 1, 2022

@undefobj - I am focused just on React JS at the moment. I could also very well be doing it wrong. I am attempting to DataStore.save() when a textarea changes (after a short delay of user inactivity). This word processor. I am not using subscribe or observe as seen in that example. I have a function in the component that gets called onChange that executes DataStore.save like this https://docs.amplify.aws/lib/datastore/data-access/q/platform/js/#create-and-update

I don't see how the example you linked lets me save iteratively at all to be honest. Even the example in the docs has you query for the original before using that to update. I know the value I want to change and the id of the thing it's on, but that doesn't seem to be enough.

@manueliglesias manueliglesias self-assigned this Jun 1, 2022
@svidgen
Copy link
Member

svidgen commented Jun 3, 2022

Seems related:

  1. fix: merge patches for consecutive copyOf #9936
  2. Missing fields in update mutation after calling .copyOf() multiple times #9891

The PR has comments indicating some discussion is needed. It probably makes sense for us to discuss these together, @manueliglesias + @dpilch.

@dpilch
Copy link
Member

dpilch commented Jun 6, 2022

I'll take a look and add to the research if it is related.

@chrisbonifacio chrisbonifacio added p1 documentation Related to documentation feature requests and removed pending-triage Issue is pending triage labels Jun 20, 2022
@alharris-at
Copy link

We've updated our docs to provide a warning for working with stale data, and have added a code sample as well (available here https://docs.amplify.aws/lib/datastore/data-access/q/platform/js/#create-and-update). We are also tracking a followup item to emit a warning in the console for users who encounter this state in the future (tracking separately).

Thank you for raising this issue!

@svidgen svidgen closed this as completed Jul 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DataStore Related to DataStore category documentation Related to documentation feature requests
Projects
None yet
Development

No branches or pull requests

8 participants