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

Api hasMany relationships are inconsistently retrieved #2459

Open
AakashKB opened this issue Apr 13, 2024 · 6 comments
Open

Api hasMany relationships are inconsistently retrieved #2459

AakashKB opened this issue Apr 13, 2024 · 6 comments

Comments

@AakashKB
Copy link

AakashKB commented Apr 13, 2024

Environment information

System:
  OS: macOS 14.4.1
  CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  Memory: 2.78 GB / 32.00 GB
  Shell: /bin/zsh
Binaries:
  Node: 20.11.1 - ~/.nvm/versions/node/v20.11.1/bin/node
  Yarn: 1.22.22 - ~/.nvm/versions/node/v20.11.1/bin/yarn
  npm: 10.2.4 - ~/.nvm/versions/node/v20.11.1/bin/npm
  pnpm: 8.10.5 - /usr/local/bin/pnpm
NPM Packages:
  @aws-amplify/backend: 0.13.0-beta.14
  @aws-amplify/backend-cli: 0.12.0-beta.16
  aws-amplify: 6.0.20
  aws-cdk: 2.133.0
  aws-cdk-lib: 2.133.0
  typescript: 5.4.2
AWS environment variables:
  AWS_STS_REGIONAL_ENDPOINTS = regional
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
No CDK environment variables%

Description

data/resources schema:

 Conversation: a
            .model({
                playerCharacterRelationship: a.belongsTo(
                    "PlayerCharacterRelationship"
                ),
                messages: a.hasMany("Message"), //add conversation context
                lastMessage: a.hasOne("Message"),
                owner: a.string(),
            })
            .authorization([a.allow.owner()]),
        Message: a
            .model({
                conversation: a.belongsTo("Conversation"),
                sender: a.string().required(),
                content: a.string().required(),
                owner: a.string(),
            })
            .authorization([a.allow.owner()]),

addNewMessage():

export const addNewMessage = async (
    userId: string,
    content: string,
    senderId: string,
    conversation: Schema["Conversation"],
) => {
    const messageData: any = {
        conversation,
        sender: senderId,
        content,
        owner: userId,
    };
    //Create Message
    const { data: message, errors } = await dataClient.models.Message.create(
        messageData
    );
    //Update conversation with last message
    const {
        data: updatedConversation,
        errors: conversationErrors,
    } = await dataClient.models.Conversation.update({
        id: conversation.id,
        lastMessage: message,
    });
    //Check if messages added
    const {
        data: newMessages,
        errors: newErrors,
    } = await updatedConversation.messages();

    return message;
};

Using the above code, when I add a message to a conversation then check the conversation.messages list, I do not always see the newly added messages.

It seems very inconsistent, sometimes the messages are added and the other times they are missing. All checked via multiple logs.

Useful info:

  • The messages are consistently added when I manually check DynamoDB, it seems the issue then is in the retrieval
  • This code is run in a lambda function, lambda has full permissions to API at the moment
  • Curious if it is cause by adding the lastMessage property to conversation with a hasOne relationship, maybe there is confusion on lastMessage vs other messages?
  • No errors output or thrown by api
  • Every time I try to retrieve messages from the conversation, it is always the same subset retrieved, and the same subset left out.

Side note:

  • This would all be a lot faster to debug and test if lambda logs were outputted on console similar to gen1 mock lambdas. It is currently annoying to check cloudwatch each time.
@AakashKB AakashKB changed the title Api has many relationships are inconsistent Api hasMany relationships are inconsistently retrieved Apr 13, 2024
@AakashKB
Copy link
Author

Further findings:

  • Removed lastMessage property, issue still persists so ruling it out as issue
  • When I pull conversation messages in front end via selectionSet, this issue does not happen, it only seems to be happening in lambda (however my lambda code retrieves via the conversation.messages() function via a new request as opposed to defining in selectionSet, testing this next.

Functioning code in frontend that retrieves all messages without issue:

const {
        data,
        errors,
    } = await amplifyClient.models.PlayerCharacterRelationship.get(
        { id },
        {
            selectionSet: ["lastConversation.*", "lastConversation.messages.*"],
        }
    );
    
const messages = data?.lastConversation?.messages;

@AakashKB
Copy link
Author

Updated lambda code to pull messages via selectionSet as opposed to using conversation.messages() function to make a new request, fixed the issue, messages are all pulled as expected.

Still keeping ticket open to track issue with conversation.messages(), my findings can be a workaround

@ykethan
Copy link

ykethan commented Apr 15, 2024

Hey,👋 thanks for raising this! I'm going to transfer this over to our API repository for better assistance 🙂

@edwardfoyle edwardfoyle transferred this issue from aws-amplify/amplify-backend Apr 15, 2024
@david-mcafee
Copy link
Member

david-mcafee commented Apr 15, 2024

@AakashKB I have not yet been able to repro this issue. Perhaps this is unrelated, but it looks like your function is returning the original message that was created, and not the retrieved messages - could you include a code snippet of where you are querying the parent / retrieving the child records, and how you are logging the output?

I was able to add both messages and lastMessage relationships, and they worked as expected. Can you potentially try adding further logging to your function to check the updates at each step (what conversation is being passed to the function, what is the output of each operation, etc). I'm wondering if the output you are seeing is from a previous update and/or query, and not the latest.

Lastly, does this only happen in Lambda?

For reference, here is my reproduction code:

    // Create parent record:
    const { data: conversation } = await client.models.Conversation.create({
      title: `${Date.now()}`,
    });

    // Create Message with parent record:
    const { data: message } = await client.models.Message.create({
      content: "First Message",
      conversation,
    });

    // Update conversation with last message
    const { data: updatedConversation } =
      await client.models.Conversation.update({
        id: conversation.id,
        lastMessage: message,
      });

    // Retrieve `hasMany` messages:
    const { data: newMessages } = await updatedConversation.messages();

    console.log("retrieve messages:", newMessages);

    // Retrieve last message:
    const { data: lastMessage } = await updatedConversation.lastMessage();

    console.log("retrieve last message:", lastMessage);

    // Create second Message, include parent record:
    const { data: secondMessage } = await client.models.Message.create({
      content: "Second Message",
      conversation,
    });

    // Update conversation with last message
    const { data: updatedConversation2 } =
      await client.models.Conversation.update({
        id: conversation.id,
        lastMessage: secondMessage,
      });

    // Retrieve `hasMany` messages after second update:
    const { data: newMessages2 } = await updatedConversation2.messages();

    console.log("retrieve messages after second update:", newMessages2);

    // Retrieve last message after second update:
    const { data: lastMessage2 } = await updatedConversation2.lastMessage();

    console.log("retrieve last message after second update:", lastMessage2);

@AakashKB
Copy link
Author

@david-mcafee I returned the message but can confirm it works without, because when I refresh the page, it pulls the latest conversation, and all the messages are present.

I logged conversation, messages, etc. at every step of the function, and it consistently confirmed my issues.

If you look at my further findings comment above, it seems only difference is whether I directly pull via .messages() vs using a selectionSet to retrieve. Already ruled out lastMessage being an issue.

Still need to verify if only on Lambda, but it consistently does happen at lambda.

@chrisbonifacio
Copy link

Hi @AakashKB can you upgrade to the latest versions of @aws-amplify/backend and @aws-amplify/backend-cli

The code you shared is an older syntax and is no longer valid in the release version of Gen 2.

The updated syntax requires a reference id for each relationship.
https://docs.amplify.aws/react/build-a-backend/data/data-modeling/relationships/

After upgrading, please let us know if the issue persists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants