Skip to content

GSI sort key not included in upsert().add() UpdateExpression #542

@briananstett

Description

@briananstett

Describe the bug
When using upsert().add() with an entity that has a GSI with a sort key, the GSI sort key (gsi1sk) is not included in the UpdateExpression. This results in the item not being properly replicated to the GSI.

I hope I'm not just missing something.

ElectroDB Version
3.5.3

ElectroDB Playground Link
Playground link

Entity/Service Definitions

{
  model: {
    entity: 'stats',
    version: '1',
    service: 'stats',
  },
  attributes: {
    metricName: {
      type: 'string',
      required: true,
    },
    metricValue: {
      type: 'number',
      required: true,
    },
    dimensionName: {
      type: 'string',
      required: true,
    },
    dimensionValue: {
      type: 'string',
      required: true,
    },
    timestamp: {
      type: 'string',
      required: true,
    },
  },
  indexes: {
    // Primary access pattern: Query by metric/dimension/value across time range
    primary: {
      pk: {
        field: 'pk',
        composite: ['metricName', 'dimensionName', 'dimensionValue'],
      },
      sk: {
        field: 'sk',
        composite: ['timestamp'],
      }
    },
    // Query top N by metric value (DynamoDB-sorted rankings)
    // Use case: Get top 10 communications by message count, top campaigns by cost
    numberSortKey: {
      index: 'gsi1pk-gsi1sk-index',
      pk: {
        field: 'gsi1pk',
        composite: ['metricName', 'dimensionName', 'metricName'],
      },
      sk: {
        field: 'gsi1sk',
        composite: ['metricValue'],
        template: '${metricValue}',
      }
    }
  },
}

Expected behavior
The UpdateExpression should include the GSI sort key (gsi1sk) when performing an upsert with add(), ensuring the item is properly indexed in the gsi1pk-gsi1sk-index.

Additional context
I have a data model where I'd like to have an access pattern with a numeric sort key so that I can perform numeric sorting.

For example, "Get top 10 campaigns by message count."

According to the docs, if I want a numeric key i need to utilize the template property of the index.

When a new item is created from the upsert().add() I see it in the main table, but if scan the GSI, there are no items (item is not replicated). If I examine the item in the main table, there is no attribute gsi1sk. If I manually add it, the item is replicated and I see it in the GSI.

{
  TableName: 'electrodb-test',
  UpdateExpression: 'SET #__edb_e__ = :__edb_e___u0, #__edb_v__ = :__edb_v___u0, #metricName = :metricName_u0, #dimensionName = :dimensionName_u0, #dimensionValue = :dimensionValue_u0, #timestamp = :timestamp_u0, #gsi1pk = :gsi1pk_u0 ADD #metricValue :metricValue_u0',
  ExpressionAttributeNames: {
    '#__edb_e__': '__edb_e__',
    '#__edb_v__': '__edb_v__',
    '#metricName': 'metricName',
    '#dimensionName': 'dimensionName',
    '#dimensionValue': 'dimensionValue',
    '#timestamp': 'timestamp',
    '#gsi1pk': 'gsi1pk',
    '#metricValue': 'metricValue'
  },
  ExpressionAttributeValues: {
    ':__edb_e___u0': 'stats',
    ':__edb_v___u0': '1',
    ':metricName_u0': 'messageCount',
    ':dimensionName_u0': 'campaignId',
    ':dimensionValue_u0': 'campgin-123',
    ':timestamp_u0': '2026-01-06T21',
    ':gsi1pk_u0': '$stats#metricname_messagecount#dimensionname_campaignid#metricname_messagecount',
    ':metricValue_u0': 1
  },
  Key: {
    pk: '$stats#metricname_messagecount#dimensionname_campaignid#dimensionvalue_campgin-123',
    sk: '$stats_1#timestamp_2026-01-06t21'
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions