Skip to content

Incorrect query results #294

@TA-5

Description

@TA-5
**Describe the bug**

When using `withIndex()` in combination with `limit()`, the package incorrectly generates a DynamoDB `Scan` 
operation instead of a `Query` operation. 

This results in:

1. Performance Issues: Scanning the entire GSI instead of querying it efficiently
2. Incorrect Results: Returns 0 results when it should return the limited number of items  
3. Wrong Operation Type: Uses `FilterExpression` (Scan) instead of `KeyConditionExpression` (Query)

The bug occurs specifically when chaining `withIndex()`, `where()`, and `limit()` together. Without `limit()`, 
the query works correctly and uses the proper Query operation.

**Schema**

Table schema:
* Primary key: Composite key `PK` (partition key), `SK` (sort key)
* GSI1: `TasksByStatusIndex`
  - Partition key: `GSI1PK` (e.g., "STATUS#OPEN")
  - Sort key: `GSI1SK` (e.g., "T")
* GSI2: `TasksByUserIndex`
  - Partition key: `GSI2PK` (e.g., "USER#123") 
  - Sort key: `GSI2SK` (e.g., "OPEN#T")

Model configuration:
```php
public function getDynamoDbIndexKeys() {
    return [
        'TasksByStatusIndex' => [
            'hash' => 'GSI1PK',
            'range' => 'GSI1SK',
        ],
        'TasksByUserIndex' => [
            'hash' => 'GSI2PK',
            'range' => 'GSI2SK',
        ],
    ];
}

Debug info

Working query (without limit):

$query = Task::withIndex('TasksByStatusIndex')->where('GSI1PK', 'STATUS#OPEN');
print_r($query->toDynamoDbQuery());

Results in proper Query operation (works correctly, returns 17 results).

Broken query (with limit):

$query = Task::withIndex('TasksByStatusIndex')->where('GSI1PK', 'STATUS#OPEN')->limit(2);
print_r($query->toDynamoDbQuery());

Output:

BaoPham\DynamoDb\RawDynamoDbQuery Object
(
    [op] => Scan        // ❌ Should be "Query"
    [query] => Array
        (
            [TableName] => local_tasks
            [FilterExpression] => #GSI1PK = :a1    // ❌ Should be "KeyConditionExpression"
            [IndexName] => TasksByStatusIndex
            [ExpressionAttributeNames] => Array
                (
                    [#GSI1PK] => GSI1PK
                )
            [ExpressionAttributeValues] => Array
                (
                    [:a1] => Array
                        (
                            [S] => STATUS#OPEN
                        )
                )
        )
)

Expected behavior: Should generate a Query operation with KeyConditionExpression and return 2 results.
Actual behavior: Generates a Scan operation with FilterExpression and returns 0 results.

Reproduction steps:

  1. Create a model extending DynamoDbModel with GSI configuration
  2. Use Model::withIndex('IndexName')->where('GSI_KEY', 'value')->limit(N)->get()
  3. Observe that it returns 0 results and uses Scan instead of Query

Workaround:
Use the raw DynamoDB client directly:

$client->query([
    'TableName' => $tableName,
    'IndexName' => 'TasksByStatusIndex',
    'KeyConditionExpression' => 'GSI1PK = :status', 
    'ExpressionAttributeValues' => [':status' => ['S' => 'STATUS#OPEN']],
    'Limit' => 2
]);

Version info

  • Laravel: 12.20.0
  • PHP: 8.3.0
  • baopham/dynamodb: 6.6.0

Edit: better formatting of the report.

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