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

Item update FAILS - error message contains broken link - need help / would like to fix docs #406

Open
iOSonntag opened this issue Jul 16, 2024 · 2 comments

Comments

@iOSonntag
Copy link
Contributor

Describe the bug
I am trying to update an item in a transaction but it fails for some reason:

I expect this to work:

Question.update({
  categoryId: categoryId,
  questionId: questionId,
})
.set({
  enabled: false,
})
.where((attr, op) => op.eq(attr.enabled, true))
...

but only this works:

Question.update({
  categoryId: categoryId,
  questionId: questionId,
})
.set({
  enabled: false,
  type: 'TEXT', // added this
})
.where((attr, op) => op.eq(attr.enabled, true))
.where((attr, op) => op.eq(attr.type, 'TEXT')) // and this to ensure consistency
...

The error in the console says the following - and I have no clue on why I need to supply this value if I am not changing it and unfortunately the link in the error message is broken.

|  +1343ms An unknown error occurred: ElectroError: Incomplete composite attributes: 
Without the composite attributes "type" the following access patterns cannot be updated:
"byTypeCategoryIdEnabled_questionId_KEYS_ONLY". 
If a composite attribute is readOnly and cannot be set, use the 'composite' chain method 
on update to supply the value for key formatting purposes. - For more detail on this error 
reference: https://electrodb.dev/en/reference/errors/#incomplete-composite-attributes

I would like to learn more on why I need to add this, but I cant find it in the documentation, any help would be appreciated, If I am guided in the right direction, I would send a Pull Request to fix the docs afterwards.

ElectroDB Version
Specify the version of ElectroDB you are using
2.14.0

Entity/Service Definitions
Include your entity model (or a model that sufficiently recreates your issue) to help troubleshoot.

export const QuestionTypes = ['TEXT', 'IMAGE'] as const;
export const RetrievedAtFormats = ['DAY', 'MONTH', 'YEAR'] as const;
export type QuestionType = typeof QuestionTypes[number];
export type QuestionEntity = EntityItem<typeof Question>;
export type CreateQuestionEntity = CreateEntityItem<typeof Question>;

export const Question = new Entity({
  model: {
    entity: 'Question',
    service: 'uquiz',
    version: '1',
  },
  attributes: {
    categoryId: {
      type: 'string',
      required: true,
    },
    questionId: {
      type: 'number',
      required: true,
      padding: {
        length: 12,
        char: '0',
      },
    },
    type: {
      type: QuestionTypes,
      required: true,
    },
    question: {
      type: 'string',
      required: true,
    },
    enabled: {
      type: 'boolean',
      required: true,
    },
    image: S3File,
    mediaSource: {
      type: 'map',
      properties: {
        name: {
          type: 'string',
          required: true,
        },
        url: {
          type: 'string',
          required: true,
        },
      },
    },
    retrieved: {
      type: 'map',
      properties: {
        at: {
          type: 'string',
          required: true,
        },
        format: {
          type: RetrievedAtFormats,
          required: true,
        },
      },
    },
    correct: {
      type: 'string',
      required: true,
    },
    incorrect0: {
      type: 'string',
      required: true,
    },
    incorrect1: {
      type: 'string',
      required: true,
    },
    incorrect2: {
      type: 'string',
      required: true,
    },
    played: {
      type: 'number',
      default: 0,
      required: true,
    },
    playedCorrectly: {
      type: 'number',
      default: 0,
      required: true,
    },
    successRate: {
      type: 'number',
      default: 1,
      required: true,
    },
    createdAt: CommonFields.createdAt,
    updatedAt: CommonFields.updatedAt,
  },
  indexes: {
    question: {
      scope: 'question',
      pk: {
        field: 'pk',
        composite: ['categoryId'],
      },
      sk: {
        field: 'sk',
        composite: ['questionId'],
      },
    },
    byTypeCategoryIdEnabled_questionId_KEYS_ONLY: {
      index: 'kgsi1',
      pk: {
        field: 'kgsi1_pk',
        composite: ['type', 'categoryId', 'enabled'],
      },
      sk: {
        field: 'kgsi1_sk',
        composite: ['questionId'],
      },
    },
    by_categoryIdquestionId_KEYS_ONLY: {
      index: 'kgsi2',
      scope: 'question',
      pk: {
        field: 'kgsi2_pk',
        composite: [],
      },
      sk: {
        field: 'kgsi2_sk',
        composite: ['categoryId', 'questionId'],
      },
    },
    byCorrect_categoryIdquestionId_KEYS_ONLY: {
      index: 'kgsi3',
      scope: 'question',
      pk: {
        field: 'kgsi3_pk',
        composite: ['correct'],
      },
      sk: {
        field: 'kgsi3_sk',
        composite: ['categoryId', 'questionId'],
      },
    },
    byCategoryIdQuestion_questionId_KEYS_ONLY: {
      index: 'kgsi4',
      scope: 'question',
      pk: {
        field: 'kgsi4_pk',
        composite: ['categoryId', 'question'],
      },
      sk: {
        field: 'kgsi4_sk',
        composite: ['questionId'],
      },
    }
  },
}, entityConfig);
@tywalch
Copy link
Owner

tywalch commented Jul 20, 2024

Hi @iOSonntag 👋

Good question! It looks like the link in the error is dead (whoops! 👎 ) but here is where it should go: https://electrodb.dev/en/reference/errors/#missing-composite-attributes

In a nutshell, one of ElectroDB's most important responsibilities is keeping indexes accurate, updated, and in sync. This last part (keeping them in sync) can be difficult because some operations could cause indexes to become out of sync. For example, if an update changes the value of a composite attribute, the impacted index field must also be rewritten. That is what is happening with your example, your change impacts attributes that contribute to the index field kgsi1_pk . ElectroDB identifies that the update will impact that index and will need to update its value as well.

Here's the rub: ElectroDB can't partially update an index. The index field kgsi1_pk has three contributing attributes: type, categoryId, and enabled. In your first query, ElectroDB has access only to categoryId and enabled at the time of update. It needs to update kgsi1_pk but does not have a value to use for type so it cannot create the string necessary to update kgsi1_pk. Your second query does include type so it is able to successfully format the key and continue.

ElectroDB does a lot of work to intelligently limit the amount this constraint impacts queries, but in the case where a key is partially being updated, there's not much else it can do but protect the integrity of the data.

Let me know if you have any further questions, and thanks for the post!

@iOSonntag
Copy link
Contributor Author

Hi @tywalch, nice to hear from you 👋🏻

Ah okay got this, thank you for your detailed explanation 👍🏻

I created a pull request #409 to fix the issue, all I did was search and replace the broken link.

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

No branches or pull requests

2 participants