diff --git a/README.md b/README.md index 856fb740..ac2e9e67 100644 --- a/README.md +++ b/README.md @@ -347,6 +347,8 @@ crud.select('customers', {{'<=', 'age', 35}}) **Note**: tuples are sorted by age because space has index `age`. Otherwise, tuples are sorted by primary key. +See more examples of select queries [here.](https://github.com/tarantool/crud/docs/select.md) + ### Pairs You can iterate across a distributed space using the `crud.pairs` function. @@ -370,6 +372,8 @@ for _, object in crud.pairs('customers', {{'<=', 'age', 35}}, {use_tomap = true} end ``` +See more examples of pairs queries [here.](https://github.com/tarantool/crud/docs/pairs.md) + ### Truncate ```lua diff --git a/doc/pairs.md b/doc/pairs.md new file mode 100644 index 00000000..bf3423a3 --- /dev/null +++ b/doc/pairs.md @@ -0,0 +1,209 @@ +# Pairs examples + +With ``crud.pairs``, you can iterate across a distributed space. +The arguments are the same as [``crud.select``](https://github.com/tarantool/crud/docs/select.md), except of the ``use_tomap`` parameter. +Below are examples that may help you. + +## Getting space + +Let's check ``developers`` space contents to make other examples more clear. Just select first 4 values without conditions. + +**Example:** + +```lua +tuples = {} +for _, tuple in crud.pairs('developers', nil, { first = 4 }) do + table.insert(tuples, tuple) +end + +tuples +--- +- - - 1 -- id + - 7331 -- bucket_id + - Alexey -- name + - Adams -- surname + - 20 -- age + - - 2 + - 899 + - Sergey + - Allred + - 21 + - - 3 + - 9661 + - Pavel + - Adams + - 27 + - - 4 + - 501 + - Mikhail + - Liston + - 51 +... +``` + +## ``use_tomap`` parameter + +With ``use_tomap`` flag, you can choose to iterate over objects or over tuples. +If ``use_tomap = true``, you will iterate over objects. This parameter is false by default. + +**Example:** + +```lua +objects = {} +for _, obj in crud.pairs('developers', nil, { use_tomap = true, first = 3 }) do + table.insert(tuples, tuple) +end + +objects +--- +- - id: 1 + bucket_id: 7331 + name: Alexey + surname: Adams + age: 20 + - id: 2 + bucket_id: 899 + name: Sergey + surname: Allred + age: 21 + - id: 3 + bucket_id: 9661 + name: Pavel + surname: Adams + age: 27 +... +``` + +## Pagination + +``crud.pairs``, like [``crud.select``](https://github.com/tarantool/crud/doc/select#pagination), supports pagination. +To use it, combine the ``first`` and ``after`` parameters. + +**Example:** + +```lua +tuples = {} +for _, tuple in crud.pairs('developers', nil, { first = 2 }) do + table.insert(tuples, tuple) -- Got first two tuples +end + +tuples +--- +- - - 1 + - 7331 + - Alexey + - Adams + - 20 + - - 2 + - 899 + - Sergey + - Allred + - 21 +... +new_tuples = {} +for _, tuple in crud.pairs('developers', nil, { after = tuples[2], first = 2 }) do + table.insert(new_tuples, tuple) -- Got next two tuples +end + +new_tuples +--- +- - - 3 + - 9661 + - Pavel + - Adams + - 27 + - - 4 + - 501 + - Mikhail + - Liston + - 51 +... +``` + +Note that ``crud.pairs``, unlike ``crud.select``, **doesn't support reverse pagination.** + +## Lua Fun + +[``Pairs``](https://github.com/tarantool/crud#pairs) is [Lua Fun](https://github.com/luafun/luafun) compatible. Some examples of working with basic functional functions below. + +**Filter example:** + +```lua +objects = {} +for _, obj in crud.pairs('developers', {{'>=', 'age', 20}}, { use_tomap = true }):filter(function(x) return x.age % 5 == 0 end) do + table.insert(objects, obj) +end + +objects +--- +- - id: 1 + bucket_id: 7331 + name: Alexey + surname: Adams + age: 20 +... +``` + +**Reduce (foldl) example:** + +```lua +age_sum = crud.pairs('developers', nil, { use_tomap = true }):reduce(function(acc, x) return acc + x.age end, 0) +age_sum +--- +- 166 +.... +``` + +**Map example:** + +```lua +objects = {} +for _, obj in crud.pairs('developers', nil, { use_tomap = true }):map(function(x) return {id = obj.id, name = obj.name, age = obj.age * 2}) do + table.insert(objects, obj) +end + +objects +--- +- - id: 1 + name: Alexey + age: 40 + - id: 2 + name: Sergey + age: 42 + - id: 3 + name: Pavel + age: 54 + - id: 4 + name: Mikhail + age: 102 + - id: 5 + name: Dmitry + age: 32 + - id: 6 + name: Alexey + age: 62 +... +``` + +**Take example**: + +```lua +tuples = {} +for _, tuple in crud.pairs('developers', {{'>=', 'age', 25}}):take(2) do + table.insert(tuples, tuple) +end + +tuples +--- +- - - 3 + - 9661 + - Pavel + - Adams + - 27 + - - 4 + - 501 + - Mikhail + - Liston + - 51 +... +``` diff --git a/doc/select.md b/doc/select.md new file mode 100644 index 00000000..d481663b --- /dev/null +++ b/doc/select.md @@ -0,0 +1,303 @@ +# Select examples + +## Filtering + +``CRUD`` allows to filter tuples by conditions. Each condition can use field name (or number) or index name. The first condition that uses index name is used to iterate over space. If there is no conditions that match index names, full scan is performed. Other conditions are used as additional filters. Search condition for the indexed field must be placed first to avoid a full scan. + +**Note:** If you specify sharding key or ``bucket_id`` select will be performed on single node. Otherwise Map-Reduce over all nodes will be occurred. + +Below are examples of filtering data using these conditions. + +### Getting space + +Let's check ``developers`` space content to make other examples more clear. Just select first 6 values without conditions. + +**Example:** + +```lua +crud.select('developers', nil, { first = 6 }) +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] + - [2, 899, 'Sergey', 'Allred', 21] + - [3, 9661, 'Pavel', 'Adams', 27] + - [4, 501, 'Mikhail', 'Liston', 51] + - [5, 1993, 'Dmitry', 'Jacobi', 16] + - [6, 8765, 'Alexey', 'Sidorov', 31] +... +``` + +### Select using index + +Let's say we have a ``age`` index. Example below gets a list of ``customers`` over 30 years old. + +**Example:** + +```lua +crud.select('developers', {{'>=', 'age', 30}}) +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [6, 8765, 'Alexey', 'Sidorov', 31] + - [4, 501, 'Mikhail', 'Liston', 51] +... +``` + +**Note:** results are sorted by age, because first condition is ``age`` index. + +### Select using composite index + +Suppose we have a composite index consisting of the ``name`` and ``surname`` fields. See example of select queries using such a composited index below. + +**Example**: + +```lua +crud.select('developers', {{'==', 'full_name', {"Alexey", "Adams"}}}) +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] +... +``` + +### Select using partial key + +Alternatively, you can use a partial key for a composite index. + +**Example**: + +```lua +crud.select('developers', {{'==', 'full_name', "Alexey"}}) +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] + - [6, 8765, 'Alexey', 'Sidorov', 31] +... +``` + +**Note:** If you specify partial key not at the first parameter (e.g. ``{{'==', 'full_name', {nil, "Sidorov"}}}``), then full scan will be performed. + +### Select using non-indexed field + +You can also make a selection using a non-indexed field. + +**Example:** + +```lua +crud.select('developers', {{'==', 'surname', "Adams"}}) +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] + - [3, 9661, 'Pavel', 'Adams', 27] +... +``` + +**Note:** in this case full scan is performed. + +### Avoiding full scan + +**Example:** + +```lua +crud.select('developers', {{'==', 'surname', "Adams"}, {'>=', 'age', 25}}) +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [3, 9661, 'Pavel', 'Adams', 27] +... +``` + +In this case, a full scan will be performed, since non-indexed field is placed first in search conditions. Example below shows how you can avoid a full scan. + +**Example:** + +```lua +crud.select('developers', {{'>=', 'age', 30}, {'==', 'surname', "Adams"}}) +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [3, 9661, 'Pavel', 'Adams', 27] +... +``` + +## Pagination + +[See more](https://github.com/tarantool/crud#select) about ``opts`` parameter. + +### ``first`` parameter + +Using the ``first`` option we will get the first **N** results of the query. + +**Example:** + +```lua +res, err = crud.select('developers', nil, { first = 3 }) +res +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] + - [2, 899, 'Sergey', 'Allred', 21] + - [3, 9661, 'Pavel', 'Adams', 27] +... +``` + +Thus, we got the first three objects from the ``developers`` space. + +### ``after`` parameter + +Using ``after``, we can get the objects after specified tuple. + +**Example:** + +```lua +res, err = crud.select('developers', nil, { after = res.rows[3] }) +res +--- +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [4, 501, 'Mikhail', 'Liston', 51] + - [5, 1993, 'Dmitry', 'Jacobi', 16] + - [6, 8765, 'Alexey', 'Sidorov', 31] +... +``` + +With this request, we got objects behind the objects from the [previous example](https://github.com/tarantool/crud/doc/select#first-parameter) + +### Combine ``first`` and ``after`` + +To use pagination, we have to combine ``after`` and ``first`` parameters. + +**Example:** + +```lua +res, err = crud.select('developers', nil, { first = 3 }) +res +--- Got first three objects +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] + - [2, 899, 'Sergey', 'Allred', 21] + - [3, 9661, 'Pavel', 'Adams', 27] +... +res, err = crud.select('developers', nil, { after = res.rows[3], first = 3 }) +res +--- Got the next three objects +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [4, 501, 'Mikhail', 'Liston', 51] + - [5, 1993, 'Dmitry', 'Jacobi', 16] + - [6, 8765, 'Alexey', 'Sidorov', 31] +... +``` + +### Reverse pagination + +Select also supports reverse pagination. To use it, pass a negative value to the ``first`` parameter and combine it with ``after`` parameter. + +**Example:** + +```lua +-- Imagine that user looks at his friends list using very small pages +-- He opens first page, then presses '->' and take next page +-- Then, he wants to return back and presses '<-' +res, err = crud.select('developers', nil, { first = 3 }) +res +--- Got first page (first three objects) +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] + - [2, 899, 'Sergey', 'Allred', 21] + - [3, 9661, 'Pavel', 'Adams', 27] +... +res, err = crud.select('developers', nil, { after = res.rows[3], first = 3 }) +res +--- Got the next page (next three objects) +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [4, 501, 'Mikhail', 'Liston', 51] + - [5, 1993, 'Dmitry', 'Jacobi', 16] + - [6, 8765, 'Alexey', 'Sidorov', 31] +... +res, err = crud.select('developers', nil, { after = res.rows[1], first = -3 }) +res +--- Got first page again +- metadata: + - {'name': 'id', 'type': 'unsigned'} + - {'name': 'bucked_id', 'type': 'unsigned'} + - {'name': 'name', 'type': 'string'} + - {'name': 'surname', 'type': 'string'} + - {'name': 'age', 'type': 'number'} + rows: + - [1, 7331, 'Alexey', 'Adams', 20] + - [2, 899, 'Sergey', 'Allred', 21] + - [3, 9661, 'Pavel', 'Adams', 27] +... +```