baopham / laravel-dynamodb

Eloquent syntax for DynamoDB
https://packagist.org/packages/baopham/dynamodb
MIT License
490 stars 128 forks source link

limit is not working #174

Closed choiks14 closed 5 years ago

choiks14 commented 5 years ago

limit and where is not working

table is simple table.

     $model = new RtuLog;
    $items = $model->where('rtu_id', '=', 1)->get();;
    dd($items->toArray());

returns below.

array:29 [▼
  0 => array:4 [▶]
  1 => array:4 [▶]
  2 => array:4 [▶]
  3 => array:4 [▶]
  4 => array:4 [▶]
  5 => array:4 [▶]
  6 => array:4 [▶]
  7 => array:4 [▶]
  8 => array:4 [▶]
  9 => array:4 [▶]
  10 => array:4 [▶]
  11 => array:4 [▶]
  12 => array:4 [▶]
  13 => array:4 [▶]
  14 => array:4 [▶]
  15 => array:4 [▶]
  16 => array:4 [▶]
  17 => array:4 [▶]
  18 => array:4 [▶]
  19 => array:4 [▶]
  20 => array:4 [▶]
  21 => array:4 [▶]
  22 => array:4 [▶]
  23 => array:4 [▶]
  24 => array:4 [▶]
  25 => array:4 [▶]
  26 => array:4 [▶]
  27 => array:4 [▶]
  28 => array:4 [▶]
]

but limit is not working

    $model = new RtuLog;
    $items = $model->where('rtu_id', '=', 1)->limit(10)->get();
    dd($items->toArray());

returns below.


[

]

if i removed where then it works.

$model = new RtuLog;
    $items = $model->limit(10)->get();
    dd($items->toArray());
array:10 [▼
  0 => array:4 [▶]
  1 => array:4 [▶]
  2 => array:4 [▶]
  3 => array:4 [▶]
  4 => array:4 [▶]
  5 => array:4 [▶]
  6 => array:4 [▶]
  7 => array:4 [▶]
  8 => array:4 [▶]
  9 => array:4 [▶]
]

how can i??

zoul0813 commented 5 years ago

DynamoDb’s use of limit is not the same as a SQLDB... in DDB, it limits the number of records that Dynamo looks through. This returns no results because the first 10 records don’t match your query.

choiks14 commented 5 years ago

@zoul0813 hmmm. ok.. how make query?

please help me.

zoe-edwards commented 5 years ago

You’d probably have to use batch:

$model = new RtuLog;

$rtus = [];

$model->chunk(10, function ($records) {
    foreach ($records as $record) {
        if ($record['rtu_id'] === 1) {
            $rtus[] = $record;
        }
    }
});

dd($items->toArray());

And using Laraveliness, this could be improved to:

$model = new RtuLog;

$rtus = collect();

$model->chunk(10, function ($records) {
    foreach ($records as $record) {
        if ($record['rtu_id'] === 1) {
            $rtus->push($record);
        }
    }
});

$rtus->dd();

And further improved again if you played around with collecting the $records in the loop.

To be honest, you might be better off not using DynamoDB if this is your requirement, as it’s not really designed for this. Or possibly you need to setup a extra index on your table.

zoul0813 commented 5 years ago

Personally, I use DynamodB and ElastiCache, with a Lambda trigger that keeps ES in sync with DDB. Then I just query ES...

I store the entire source of the DDB record in ES and just build my model from that, which allows me to update it and write it back. Keeps my DDB costs down as I don’t have to worry about read/writes being too high and a small ES instance covers my needs perfectly (with caching also enabled).

zoul0813 commented 5 years ago

@thomasedwards is correct though, if you want to use DynamoDB only ... then you'll have to chunk the data until you've retrieved the "limit" you want.

$model = new RtuLog;
$rtus = [];
$model->chunk(10, function ($records) {
    foreach ($records as $record) {
        if ($record['rtu_id'] === 1) {
            $rtus[] = $record;
        }
        if(count($record) >= $LIMIT) return false;
    }
});

dd($items->toArray());

@baopham it looks like the DynamoDbQueryBuilder doesn't follow the Eloquent code? Eloquent wraps the callback with a check to see if the developer returned false, and breaks out of the loop if they did ... laravel-dynamodb runs the loop indefinitely until all records have been processed.

Check out laravel/framework/src/Illuminate/Database/Concerns/BuildsQueries.php and compare it to the implementation in DynamoDbQueryBuilder.php

baopham commented 5 years ago

Yeah, probably we should have forced it to be $model->limit(10)->where('rtu_id', 1)->get() 😅

For references:

For example, suppose you Query a table, with a Limit value of 6, and without a filter expression. The Query result will contain the first six items from the table that match the key condition expression from the request.

Now suppose you add a filter expression to the Query. In this case, DynamoDB will apply the filter expression to the six items that were returned, discarding those that do not match. The final Query result will contain 6 items or fewer, depending on the number of items that were filtered

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.Limit

A single Scan operation will read up to the maximum number of items set (if using the Limit parameter) or a maximum of 1 MB of data and then apply any filtering to the results using FilterExpression

https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html

@choiks14 Do you have what you need? Do you need more help with this?

baopham commented 5 years ago

Closing as there is already an answer.