monday_ruby 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.env +1 -1
- data/.rspec +0 -1
- data/.rubocop.yml +19 -0
- data/.simplecov +1 -0
- data/CHANGELOG.md +49 -0
- data/CONTRIBUTING.md +165 -0
- data/README.md +167 -88
- data/docs/.vitepress/config.mjs +255 -0
- data/docs/.vitepress/theme/index.js +4 -0
- data/docs/.vitepress/theme/style.css +43 -0
- data/docs/README.md +80 -0
- data/docs/explanation/architecture.md +507 -0
- data/docs/explanation/best-practices/errors.md +478 -0
- data/docs/explanation/best-practices/performance.md +1084 -0
- data/docs/explanation/best-practices/rate-limiting.md +630 -0
- data/docs/explanation/best-practices/testing.md +820 -0
- data/docs/explanation/column-values.md +857 -0
- data/docs/explanation/design.md +795 -0
- data/docs/explanation/graphql.md +356 -0
- data/docs/explanation/migration/v1.md +808 -0
- data/docs/explanation/pagination.md +447 -0
- data/docs/guides/advanced/batch.md +1274 -0
- data/docs/guides/advanced/complex-queries.md +1114 -0
- data/docs/guides/advanced/errors.md +818 -0
- data/docs/guides/advanced/pagination.md +934 -0
- data/docs/guides/advanced/rate-limiting.md +981 -0
- data/docs/guides/authentication.md +286 -0
- data/docs/guides/boards/create.md +386 -0
- data/docs/guides/boards/delete.md +405 -0
- data/docs/guides/boards/duplicate.md +511 -0
- data/docs/guides/boards/query.md +530 -0
- data/docs/guides/boards/update.md +453 -0
- data/docs/guides/columns/create.md +452 -0
- data/docs/guides/columns/metadata.md +492 -0
- data/docs/guides/columns/query.md +455 -0
- data/docs/guides/columns/update-multiple.md +459 -0
- data/docs/guides/columns/update-values.md +509 -0
- data/docs/guides/files/add-to-column.md +40 -0
- data/docs/guides/files/add-to-update.md +37 -0
- data/docs/guides/files/clear-column.md +33 -0
- data/docs/guides/first-request.md +285 -0
- data/docs/guides/folders/manage.md +750 -0
- data/docs/guides/groups/items.md +626 -0
- data/docs/guides/groups/manage.md +501 -0
- data/docs/guides/installation.md +169 -0
- data/docs/guides/items/create.md +493 -0
- data/docs/guides/items/delete.md +514 -0
- data/docs/guides/items/query.md +605 -0
- data/docs/guides/items/subitems.md +483 -0
- data/docs/guides/items/update.md +699 -0
- data/docs/guides/updates/manage.md +619 -0
- data/docs/guides/use-cases/dashboard.md +1421 -0
- data/docs/guides/use-cases/import.md +1962 -0
- data/docs/guides/use-cases/task-management.md +1381 -0
- data/docs/guides/workspaces/manage.md +502 -0
- data/docs/index.md +69 -0
- data/docs/package-lock.json +2468 -0
- data/docs/package.json +13 -0
- data/docs/reference/client.md +540 -0
- data/docs/reference/configuration.md +586 -0
- data/docs/reference/errors.md +693 -0
- data/docs/reference/resources/account.md +208 -0
- data/docs/reference/resources/activity-log.md +369 -0
- data/docs/reference/resources/board-view.md +359 -0
- data/docs/reference/resources/board.md +393 -0
- data/docs/reference/resources/column.md +543 -0
- data/docs/reference/resources/file.md +236 -0
- data/docs/reference/resources/folder.md +386 -0
- data/docs/reference/resources/group.md +507 -0
- data/docs/reference/resources/item.md +348 -0
- data/docs/reference/resources/subitem.md +267 -0
- data/docs/reference/resources/update.md +259 -0
- data/docs/reference/resources/workspace.md +213 -0
- data/docs/reference/response.md +560 -0
- data/docs/tutorial/first-integration.md +713 -0
- data/lib/monday/client.rb +41 -2
- data/lib/monday/configuration.rb +13 -0
- data/lib/monday/deprecation.rb +23 -0
- data/lib/monday/error.rb +5 -2
- data/lib/monday/request.rb +19 -1
- data/lib/monday/resources/base.rb +4 -0
- data/lib/monday/resources/board.rb +52 -0
- data/lib/monday/resources/column.rb +6 -0
- data/lib/monday/resources/file.rb +56 -0
- data/lib/monday/resources/folder.rb +55 -0
- data/lib/monday/resources/group.rb +66 -0
- data/lib/monday/resources/item.rb +62 -0
- data/lib/monday/util.rb +33 -1
- data/lib/monday/version.rb +1 -1
- data/lib/monday_ruby.rb +1 -0
- metadata +92 -11
- data/monday_ruby.gemspec +0 -39
|
@@ -0,0 +1,934 @@
|
|
|
1
|
+
# Pagination
|
|
2
|
+
|
|
3
|
+
Learn how to efficiently paginate through large datasets using monday_ruby's cursor-based pagination methods.
|
|
4
|
+
|
|
5
|
+
## What is Cursor-Based Pagination?
|
|
6
|
+
|
|
7
|
+
Cursor-based pagination is a technique for retrieving large datasets in smaller, manageable chunks. Instead of using page numbers, it uses a cursor (an encoded string) that marks your position in the dataset.
|
|
8
|
+
|
|
9
|
+
**Key characteristics:**
|
|
10
|
+
|
|
11
|
+
- **Efficient**: Works well with large datasets without performance degradation
|
|
12
|
+
- **Consistent**: Results remain stable even when data changes during pagination
|
|
13
|
+
- **Time-limited**: Cursors expire after 60 minutes of inactivity
|
|
14
|
+
- **Configurable**: Supports page sizes from 1 to 500 items (default: 25)
|
|
15
|
+
|
|
16
|
+
**How it works:**
|
|
17
|
+
|
|
18
|
+
1. Make an initial request without a cursor to get the first page
|
|
19
|
+
2. The response includes items and a cursor for the next page
|
|
20
|
+
3. Use the cursor to fetch subsequent pages
|
|
21
|
+
4. When cursor is `null`, you've reached the end
|
|
22
|
+
|
|
23
|
+
## Basic Pagination
|
|
24
|
+
|
|
25
|
+
### Paginate Board Items
|
|
26
|
+
|
|
27
|
+
Fetch items from a board in pages:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
require "monday_ruby"
|
|
31
|
+
|
|
32
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
33
|
+
|
|
34
|
+
# Fetch first page (25 items by default)
|
|
35
|
+
response = client.board.items_page(board_ids: 12345)
|
|
36
|
+
|
|
37
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
38
|
+
items = items_page["items"]
|
|
39
|
+
cursor = items_page["cursor"]
|
|
40
|
+
|
|
41
|
+
puts "Fetched #{items.length} items"
|
|
42
|
+
puts "Cursor for next page: #{cursor}"
|
|
43
|
+
|
|
44
|
+
# Process items
|
|
45
|
+
items.each do |item|
|
|
46
|
+
puts "Item #{item['id']}: #{item['name']}"
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Fetch Next Page
|
|
51
|
+
|
|
52
|
+
Use the cursor to get the next page:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
# Fetch second page using cursor from first page
|
|
56
|
+
response = client.board.items_page(
|
|
57
|
+
board_ids: 12345,
|
|
58
|
+
cursor: cursor
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
62
|
+
next_items = items_page["items"]
|
|
63
|
+
next_cursor = items_page["cursor"]
|
|
64
|
+
|
|
65
|
+
puts "Fetched #{next_items.length} more items"
|
|
66
|
+
puts "Has more pages: #{!next_cursor.nil?}"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Custom Page Size
|
|
70
|
+
|
|
71
|
+
Adjust the number of items per page (max 500):
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
# Fetch 100 items per page
|
|
75
|
+
response = client.board.items_page(
|
|
76
|
+
board_ids: 12345,
|
|
77
|
+
limit: 100
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
81
|
+
puts "Fetched #{items_page['items'].length} items"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Fetch All Pages
|
|
85
|
+
|
|
86
|
+
### Iterate Through All Items
|
|
87
|
+
|
|
88
|
+
Use a loop to fetch all pages automatically:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
require "monday_ruby"
|
|
92
|
+
|
|
93
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
94
|
+
board_id = 12345
|
|
95
|
+
|
|
96
|
+
all_items = []
|
|
97
|
+
cursor = nil
|
|
98
|
+
|
|
99
|
+
loop do
|
|
100
|
+
# Fetch page
|
|
101
|
+
response = client.board.items_page(
|
|
102
|
+
board_ids: board_id,
|
|
103
|
+
limit: 100,
|
|
104
|
+
cursor: cursor
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
108
|
+
items = items_page["items"]
|
|
109
|
+
cursor = items_page["cursor"]
|
|
110
|
+
|
|
111
|
+
# Add items to collection
|
|
112
|
+
all_items.concat(items)
|
|
113
|
+
|
|
114
|
+
puts "Fetched #{items.length} items (Total: #{all_items.length})"
|
|
115
|
+
|
|
116
|
+
# Break if no more pages
|
|
117
|
+
break if cursor.nil?
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
puts "Retrieved all #{all_items.length} items from the board"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### With Progress Tracking
|
|
124
|
+
|
|
125
|
+
Add progress indicators for large datasets:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
require "monday_ruby"
|
|
129
|
+
|
|
130
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
131
|
+
board_id = 12345
|
|
132
|
+
|
|
133
|
+
all_items = []
|
|
134
|
+
cursor = nil
|
|
135
|
+
page_number = 1
|
|
136
|
+
|
|
137
|
+
loop do
|
|
138
|
+
puts "Fetching page #{page_number}..."
|
|
139
|
+
|
|
140
|
+
response = client.board.items_page(
|
|
141
|
+
board_ids: board_id,
|
|
142
|
+
limit: 100,
|
|
143
|
+
cursor: cursor
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
147
|
+
items = items_page["items"]
|
|
148
|
+
cursor = items_page["cursor"]
|
|
149
|
+
|
|
150
|
+
all_items.concat(items)
|
|
151
|
+
|
|
152
|
+
puts " -> Got #{items.length} items (Total: #{all_items.length})"
|
|
153
|
+
|
|
154
|
+
break if cursor.nil?
|
|
155
|
+
|
|
156
|
+
page_number += 1
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
puts "\nCompleted! Total items: #{all_items.length}"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Paginate Group Items
|
|
163
|
+
|
|
164
|
+
Fetch items from specific groups with pagination:
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
require "monday_ruby"
|
|
168
|
+
|
|
169
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
170
|
+
|
|
171
|
+
# Fetch first page from a group
|
|
172
|
+
response = client.group.items_page(
|
|
173
|
+
board_ids: 12345,
|
|
174
|
+
group_ids: "group_1",
|
|
175
|
+
limit: 50
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
items_page = response.dig("data", "boards", 0, "groups", 0, "items_page")
|
|
179
|
+
items = items_page["items"]
|
|
180
|
+
cursor = items_page["cursor"]
|
|
181
|
+
|
|
182
|
+
puts "Fetched #{items.length} items from group"
|
|
183
|
+
|
|
184
|
+
# Fetch next page
|
|
185
|
+
if cursor
|
|
186
|
+
next_response = client.group.items_page(
|
|
187
|
+
board_ids: 12345,
|
|
188
|
+
group_ids: "group_1",
|
|
189
|
+
cursor: cursor
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
next_items_page = next_response.dig("data", "boards", 0, "groups", 0, "items_page")
|
|
193
|
+
puts "Fetched #{next_items_page['items'].length} more items"
|
|
194
|
+
end
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Multiple Groups
|
|
198
|
+
|
|
199
|
+
Paginate items from multiple groups:
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
# Fetch from multiple groups
|
|
203
|
+
response = client.group.items_page(
|
|
204
|
+
board_ids: 12345,
|
|
205
|
+
group_ids: ["group_1", "group_2", "group_3"],
|
|
206
|
+
limit: 100
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# Items are returned across all specified groups
|
|
210
|
+
boards = response.dig("data", "boards")
|
|
211
|
+
boards.each_with_index do |board, board_index|
|
|
212
|
+
board["groups"].each_with_index do |group, group_index|
|
|
213
|
+
items_page = group["items_page"]
|
|
214
|
+
items = items_page["items"]
|
|
215
|
+
|
|
216
|
+
puts "Board #{board_index}, Group #{group_index}: #{items.length} items"
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Fetch All Group Items
|
|
222
|
+
|
|
223
|
+
Loop through all pages of a group:
|
|
224
|
+
|
|
225
|
+
```ruby
|
|
226
|
+
require "monday_ruby"
|
|
227
|
+
|
|
228
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
229
|
+
|
|
230
|
+
all_group_items = []
|
|
231
|
+
cursor = nil
|
|
232
|
+
|
|
233
|
+
loop do
|
|
234
|
+
response = client.group.items_page(
|
|
235
|
+
board_ids: 12345,
|
|
236
|
+
group_ids: "topics",
|
|
237
|
+
limit: 100,
|
|
238
|
+
cursor: cursor
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
items_page = response.dig("data", "boards", 0, "groups", 0, "items_page")
|
|
242
|
+
items = items_page["items"]
|
|
243
|
+
cursor = items_page["cursor"]
|
|
244
|
+
|
|
245
|
+
all_group_items.concat(items)
|
|
246
|
+
|
|
247
|
+
break if cursor.nil?
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
puts "Total items in group: #{all_group_items.length}"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Filter and Paginate
|
|
254
|
+
|
|
255
|
+
### Filter by Column Values
|
|
256
|
+
|
|
257
|
+
Use `page_by_column_values` to filter and paginate simultaneously:
|
|
258
|
+
|
|
259
|
+
```ruby
|
|
260
|
+
require "monday_ruby"
|
|
261
|
+
|
|
262
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
263
|
+
|
|
264
|
+
# Find all items where status is "Done" or "Working on it"
|
|
265
|
+
response = client.item.page_by_column_values(
|
|
266
|
+
board_id: 12345,
|
|
267
|
+
columns: [
|
|
268
|
+
{
|
|
269
|
+
column_id: "status",
|
|
270
|
+
column_values: ["Done", "Working on it"]
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
limit: 50
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
items_page = response.dig("data", "items_page_by_column_values")
|
|
277
|
+
items = items_page["items"]
|
|
278
|
+
cursor = items_page["cursor"]
|
|
279
|
+
|
|
280
|
+
puts "Found #{items.length} items with matching status"
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Multiple Filter Criteria
|
|
284
|
+
|
|
285
|
+
Combine multiple column filters (uses AND logic):
|
|
286
|
+
|
|
287
|
+
```ruby
|
|
288
|
+
# Find high-priority items assigned to specific people
|
|
289
|
+
response = client.item.page_by_column_values(
|
|
290
|
+
board_id: 12345,
|
|
291
|
+
columns: [
|
|
292
|
+
{
|
|
293
|
+
column_id: "priority",
|
|
294
|
+
column_values: ["High", "Critical"]
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
column_id: "person",
|
|
298
|
+
column_values: ["John Doe", "Jane Smith"]
|
|
299
|
+
}
|
|
300
|
+
],
|
|
301
|
+
limit: 100
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
items_page = response.dig("data", "items_page_by_column_values")
|
|
305
|
+
items = items_page["items"]
|
|
306
|
+
|
|
307
|
+
puts "Found #{items.length} high-priority items assigned to team members"
|
|
308
|
+
|
|
309
|
+
items.each do |item|
|
|
310
|
+
puts " - #{item['name']}"
|
|
311
|
+
end
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Paginate Filtered Results
|
|
315
|
+
|
|
316
|
+
Fetch all pages of filtered items:
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
require "monday_ruby"
|
|
320
|
+
|
|
321
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
322
|
+
board_id = 12345
|
|
323
|
+
|
|
324
|
+
all_filtered_items = []
|
|
325
|
+
cursor = nil
|
|
326
|
+
|
|
327
|
+
# Define filter criteria
|
|
328
|
+
filter_columns = [
|
|
329
|
+
{
|
|
330
|
+
column_id: "status",
|
|
331
|
+
column_values: ["Done"]
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
|
|
335
|
+
# First page with filter
|
|
336
|
+
response = client.item.page_by_column_values(
|
|
337
|
+
board_id: board_id,
|
|
338
|
+
columns: filter_columns,
|
|
339
|
+
limit: 100
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
items_page = response.dig("data", "items_page_by_column_values")
|
|
343
|
+
all_filtered_items.concat(items_page["items"])
|
|
344
|
+
cursor = items_page["cursor"]
|
|
345
|
+
|
|
346
|
+
# Subsequent pages (columns parameter not needed)
|
|
347
|
+
while cursor
|
|
348
|
+
response = client.item.page_by_column_values(
|
|
349
|
+
board_id: board_id,
|
|
350
|
+
cursor: cursor,
|
|
351
|
+
limit: 100
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
items_page = response.dig("data", "items_page_by_column_values")
|
|
355
|
+
all_filtered_items.concat(items_page["items"])
|
|
356
|
+
cursor = items_page["cursor"]
|
|
357
|
+
|
|
358
|
+
puts "Fetched page... Total so far: #{all_filtered_items.length}"
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
puts "Total completed items: #{all_filtered_items.length}"
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Supported Column Types
|
|
365
|
+
|
|
366
|
+
`page_by_column_values` supports filtering on these column types:
|
|
367
|
+
|
|
368
|
+
- Checkbox
|
|
369
|
+
- Country
|
|
370
|
+
- Date
|
|
371
|
+
- Dropdown
|
|
372
|
+
- Email
|
|
373
|
+
- Hour
|
|
374
|
+
- Link
|
|
375
|
+
- Long Text
|
|
376
|
+
- Numbers
|
|
377
|
+
- People
|
|
378
|
+
- Phone
|
|
379
|
+
- Status
|
|
380
|
+
- Text
|
|
381
|
+
- Timeline
|
|
382
|
+
- World Clock
|
|
383
|
+
|
|
384
|
+
**Note:** When using multiple column filters, they are combined with AND logic. Values within a single column use ANY_OF logic.
|
|
385
|
+
|
|
386
|
+
## Advanced Techniques
|
|
387
|
+
|
|
388
|
+
### Custom Field Selection
|
|
389
|
+
|
|
390
|
+
Optimize performance by requesting only needed fields:
|
|
391
|
+
|
|
392
|
+
```ruby
|
|
393
|
+
# Fetch minimal fields for faster pagination
|
|
394
|
+
response = client.board.items_page(
|
|
395
|
+
board_ids: 12345,
|
|
396
|
+
limit: 500,
|
|
397
|
+
select: ["id", "name"]
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
# Fetch with column values
|
|
401
|
+
response = client.board.items_page(
|
|
402
|
+
board_ids: 12345,
|
|
403
|
+
limit: 100,
|
|
404
|
+
select: [
|
|
405
|
+
"id",
|
|
406
|
+
"name",
|
|
407
|
+
{ column_values: ["id", "text", "value"] }
|
|
408
|
+
]
|
|
409
|
+
)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Handle Cursor Expiration
|
|
413
|
+
|
|
414
|
+
Cursors expire after 60 minutes. Handle expiration gracefully:
|
|
415
|
+
|
|
416
|
+
```ruby
|
|
417
|
+
require "monday_ruby"
|
|
418
|
+
|
|
419
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
420
|
+
board_id = 12345
|
|
421
|
+
|
|
422
|
+
all_items = []
|
|
423
|
+
cursor = nil
|
|
424
|
+
|
|
425
|
+
begin
|
|
426
|
+
loop do
|
|
427
|
+
response = client.board.items_page(
|
|
428
|
+
board_ids: board_id,
|
|
429
|
+
limit: 100,
|
|
430
|
+
cursor: cursor
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
434
|
+
items = items_page["items"]
|
|
435
|
+
cursor = items_page["cursor"]
|
|
436
|
+
|
|
437
|
+
all_items.concat(items)
|
|
438
|
+
|
|
439
|
+
break if cursor.nil?
|
|
440
|
+
|
|
441
|
+
# Optional: Add delay to avoid rate limits
|
|
442
|
+
sleep(0.5)
|
|
443
|
+
end
|
|
444
|
+
rescue Monday::ComplexityException => e
|
|
445
|
+
puts "Rate limit exceeded. Waiting before retry..."
|
|
446
|
+
sleep(60)
|
|
447
|
+
retry
|
|
448
|
+
rescue Monday::Error => e
|
|
449
|
+
puts "Error during pagination: #{e.message}"
|
|
450
|
+
puts "Successfully retrieved #{all_items.length} items before error"
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
puts "Total items: #{all_items.length}"
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Process Items in Batches
|
|
457
|
+
|
|
458
|
+
Process items as you paginate for memory efficiency:
|
|
459
|
+
|
|
460
|
+
```ruby
|
|
461
|
+
require "monday_ruby"
|
|
462
|
+
require "csv"
|
|
463
|
+
|
|
464
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
465
|
+
board_id = 12345
|
|
466
|
+
|
|
467
|
+
cursor = nil
|
|
468
|
+
total_processed = 0
|
|
469
|
+
|
|
470
|
+
# Export to CSV in batches
|
|
471
|
+
CSV.open("items_export.csv", "w") do |csv|
|
|
472
|
+
csv << ["ID", "Name", "Created At"]
|
|
473
|
+
|
|
474
|
+
loop do
|
|
475
|
+
response = client.board.items_page(
|
|
476
|
+
board_ids: board_id,
|
|
477
|
+
limit: 100,
|
|
478
|
+
cursor: cursor,
|
|
479
|
+
select: ["id", "name", "created_at"]
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
483
|
+
items = items_page["items"]
|
|
484
|
+
cursor = items_page["cursor"]
|
|
485
|
+
|
|
486
|
+
# Process batch
|
|
487
|
+
items.each do |item|
|
|
488
|
+
csv << [item["id"], item["name"], item["created_at"]]
|
|
489
|
+
total_processed += 1
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
puts "Processed #{total_processed} items..."
|
|
493
|
+
|
|
494
|
+
break if cursor.nil?
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
puts "Export complete! Total items: #{total_processed}"
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Parallel Processing
|
|
502
|
+
|
|
503
|
+
Fetch items from multiple boards simultaneously:
|
|
504
|
+
|
|
505
|
+
```ruby
|
|
506
|
+
require "monday_ruby"
|
|
507
|
+
require "concurrent"
|
|
508
|
+
|
|
509
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
510
|
+
board_ids = [12345, 67890, 11111]
|
|
511
|
+
|
|
512
|
+
# Create thread pool
|
|
513
|
+
pool = Concurrent::FixedThreadPool.new(3)
|
|
514
|
+
|
|
515
|
+
# Track results
|
|
516
|
+
results = Concurrent::Hash.new
|
|
517
|
+
|
|
518
|
+
board_ids.each do |board_id|
|
|
519
|
+
pool.post do
|
|
520
|
+
items = []
|
|
521
|
+
cursor = nil
|
|
522
|
+
|
|
523
|
+
loop do
|
|
524
|
+
response = client.board.items_page(
|
|
525
|
+
board_ids: board_id,
|
|
526
|
+
limit: 100,
|
|
527
|
+
cursor: cursor
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
531
|
+
items.concat(items_page["items"])
|
|
532
|
+
cursor = items_page["cursor"]
|
|
533
|
+
|
|
534
|
+
break if cursor.nil?
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
results[board_id] = items
|
|
538
|
+
puts "Board #{board_id}: #{items.length} items"
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
# Wait for completion
|
|
543
|
+
pool.shutdown
|
|
544
|
+
pool.wait_for_termination
|
|
545
|
+
|
|
546
|
+
puts "\nTotal items across all boards: #{results.values.flatten.length}"
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Best Practices
|
|
550
|
+
|
|
551
|
+
### Optimal Page Size
|
|
552
|
+
|
|
553
|
+
Choose the right page size for your use case:
|
|
554
|
+
|
|
555
|
+
```ruby
|
|
556
|
+
# Small pages (25-50): Better for real-time processing
|
|
557
|
+
client.board.items_page(board_ids: 12345, limit: 25)
|
|
558
|
+
|
|
559
|
+
# Medium pages (100-200): Balanced performance
|
|
560
|
+
client.board.items_page(board_ids: 12345, limit: 100)
|
|
561
|
+
|
|
562
|
+
# Large pages (300-500): Minimize API calls
|
|
563
|
+
client.board.items_page(board_ids: 12345, limit: 500)
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Guidelines:**
|
|
567
|
+
|
|
568
|
+
- Use **25-50** items when processing data in real-time
|
|
569
|
+
- Use **100-200** items for balanced performance
|
|
570
|
+
- Use **300-500** items to minimize API calls for large datasets
|
|
571
|
+
- Never exceed 500 (API limit)
|
|
572
|
+
|
|
573
|
+
### Error Handling
|
|
574
|
+
|
|
575
|
+
Always handle pagination errors:
|
|
576
|
+
|
|
577
|
+
```ruby
|
|
578
|
+
require "monday_ruby"
|
|
579
|
+
|
|
580
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
581
|
+
|
|
582
|
+
all_items = []
|
|
583
|
+
cursor = nil
|
|
584
|
+
retry_count = 0
|
|
585
|
+
max_retries = 3
|
|
586
|
+
|
|
587
|
+
loop do
|
|
588
|
+
begin
|
|
589
|
+
response = client.board.items_page(
|
|
590
|
+
board_ids: 12345,
|
|
591
|
+
limit: 100,
|
|
592
|
+
cursor: cursor
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
596
|
+
items = items_page["items"]
|
|
597
|
+
cursor = items_page["cursor"]
|
|
598
|
+
|
|
599
|
+
all_items.concat(items)
|
|
600
|
+
retry_count = 0 # Reset on success
|
|
601
|
+
|
|
602
|
+
break if cursor.nil?
|
|
603
|
+
|
|
604
|
+
rescue Monday::ComplexityException => e
|
|
605
|
+
# Rate limit exceeded
|
|
606
|
+
if retry_count < max_retries
|
|
607
|
+
retry_count += 1
|
|
608
|
+
puts "Rate limited. Retry #{retry_count}/#{max_retries} in 60s..."
|
|
609
|
+
sleep(60)
|
|
610
|
+
retry
|
|
611
|
+
else
|
|
612
|
+
puts "Max retries exceeded. Collected #{all_items.length} items."
|
|
613
|
+
break
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
rescue Monday::AuthorizationException => e
|
|
617
|
+
puts "Authorization error: #{e.message}"
|
|
618
|
+
break
|
|
619
|
+
|
|
620
|
+
rescue Monday::Error => e
|
|
621
|
+
puts "Unexpected error: #{e.message}"
|
|
622
|
+
break
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
puts "Total items retrieved: #{all_items.length}"
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### Cursor Storage
|
|
630
|
+
|
|
631
|
+
Store cursors for resumable pagination:
|
|
632
|
+
|
|
633
|
+
```ruby
|
|
634
|
+
require "monday_ruby"
|
|
635
|
+
require "json"
|
|
636
|
+
|
|
637
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
638
|
+
board_id = 12345
|
|
639
|
+
|
|
640
|
+
# Load saved cursor
|
|
641
|
+
cursor = nil
|
|
642
|
+
if File.exist?("pagination_state.json")
|
|
643
|
+
state = JSON.parse(File.read("pagination_state.json"))
|
|
644
|
+
cursor = state["cursor"]
|
|
645
|
+
puts "Resuming from saved cursor"
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# Paginate
|
|
649
|
+
loop do
|
|
650
|
+
response = client.board.items_page(
|
|
651
|
+
board_ids: board_id,
|
|
652
|
+
limit: 100,
|
|
653
|
+
cursor: cursor
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
657
|
+
items = items_page["items"]
|
|
658
|
+
cursor = items_page["cursor"]
|
|
659
|
+
|
|
660
|
+
# Process items
|
|
661
|
+
items.each do |item|
|
|
662
|
+
puts "Processing: #{item['name']}"
|
|
663
|
+
# Your processing logic here
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
# Save cursor for resume capability
|
|
667
|
+
if cursor
|
|
668
|
+
File.write("pagination_state.json", JSON.dump({ cursor: cursor }))
|
|
669
|
+
else
|
|
670
|
+
File.delete("pagination_state.json") if File.exist?("pagination_state.json")
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
break if cursor.nil?
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
puts "Pagination complete"
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### Rate Limiting
|
|
680
|
+
|
|
681
|
+
Add delays to avoid hitting rate limits:
|
|
682
|
+
|
|
683
|
+
```ruby
|
|
684
|
+
require "monday_ruby"
|
|
685
|
+
|
|
686
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
687
|
+
|
|
688
|
+
all_items = []
|
|
689
|
+
cursor = nil
|
|
690
|
+
|
|
691
|
+
loop do
|
|
692
|
+
response = client.board.items_page(
|
|
693
|
+
board_ids: 12345,
|
|
694
|
+
limit: 100,
|
|
695
|
+
cursor: cursor
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
699
|
+
items = items_page["items"]
|
|
700
|
+
cursor = items_page["cursor"]
|
|
701
|
+
|
|
702
|
+
all_items.concat(items)
|
|
703
|
+
|
|
704
|
+
break if cursor.nil?
|
|
705
|
+
|
|
706
|
+
# Add delay between requests
|
|
707
|
+
sleep(0.5) # 500ms delay
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
puts "Total items: #{all_items.length}"
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
## Common Patterns
|
|
714
|
+
|
|
715
|
+
### Count Total Items
|
|
716
|
+
|
|
717
|
+
Count items without storing them all:
|
|
718
|
+
|
|
719
|
+
```ruby
|
|
720
|
+
require "monday_ruby"
|
|
721
|
+
|
|
722
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
723
|
+
|
|
724
|
+
total_count = 0
|
|
725
|
+
cursor = nil
|
|
726
|
+
|
|
727
|
+
loop do
|
|
728
|
+
response = client.board.items_page(
|
|
729
|
+
board_ids: 12345,
|
|
730
|
+
limit: 500,
|
|
731
|
+
cursor: cursor,
|
|
732
|
+
select: ["id"] # Minimal data
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
736
|
+
total_count += items_page["items"].length
|
|
737
|
+
cursor = items_page["cursor"]
|
|
738
|
+
|
|
739
|
+
break if cursor.nil?
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
puts "Total items on board: #{total_count}"
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### Find Specific Item
|
|
746
|
+
|
|
747
|
+
Stop pagination when you find what you need:
|
|
748
|
+
|
|
749
|
+
```ruby
|
|
750
|
+
require "monday_ruby"
|
|
751
|
+
|
|
752
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
753
|
+
|
|
754
|
+
target_name = "Project Alpha"
|
|
755
|
+
found_item = nil
|
|
756
|
+
cursor = nil
|
|
757
|
+
|
|
758
|
+
loop do
|
|
759
|
+
response = client.board.items_page(
|
|
760
|
+
board_ids: 12345,
|
|
761
|
+
limit: 100,
|
|
762
|
+
cursor: cursor
|
|
763
|
+
)
|
|
764
|
+
|
|
765
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
766
|
+
items = items_page["items"]
|
|
767
|
+
cursor = items_page["cursor"]
|
|
768
|
+
|
|
769
|
+
# Search in current page
|
|
770
|
+
found_item = items.find { |item| item["name"] == target_name }
|
|
771
|
+
|
|
772
|
+
break if found_item || cursor.nil?
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
if found_item
|
|
776
|
+
puts "Found item: #{found_item['id']}"
|
|
777
|
+
else
|
|
778
|
+
puts "Item not found"
|
|
779
|
+
end
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
### Aggregate Data
|
|
783
|
+
|
|
784
|
+
Calculate statistics across all pages:
|
|
785
|
+
|
|
786
|
+
```ruby
|
|
787
|
+
require "monday_ruby"
|
|
788
|
+
|
|
789
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
790
|
+
|
|
791
|
+
stats = {
|
|
792
|
+
total: 0,
|
|
793
|
+
by_group: Hash.new(0)
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
cursor = nil
|
|
797
|
+
|
|
798
|
+
loop do
|
|
799
|
+
response = client.board.items_page(
|
|
800
|
+
board_ids: 12345,
|
|
801
|
+
limit: 100,
|
|
802
|
+
cursor: cursor,
|
|
803
|
+
select: ["id", "name", { group: ["id", "title"] }]
|
|
804
|
+
)
|
|
805
|
+
|
|
806
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
807
|
+
items = items_page["items"]
|
|
808
|
+
cursor = items_page["cursor"]
|
|
809
|
+
|
|
810
|
+
items.each do |item|
|
|
811
|
+
stats[:total] += 1
|
|
812
|
+
group_id = item.dig("group", "id")
|
|
813
|
+
stats[:by_group][group_id] += 1 if group_id
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
break if cursor.nil?
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
puts "Total items: #{stats[:total]}"
|
|
820
|
+
puts "\nItems per group:"
|
|
821
|
+
stats[:by_group].each do |group_id, count|
|
|
822
|
+
puts " #{group_id}: #{count}"
|
|
823
|
+
end
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
## Troubleshooting
|
|
827
|
+
|
|
828
|
+
### Cursor Expired
|
|
829
|
+
|
|
830
|
+
**Problem:** Cursor returns an error after 60 minutes.
|
|
831
|
+
|
|
832
|
+
**Solution:** Restart pagination from the beginning or implement cursor storage.
|
|
833
|
+
|
|
834
|
+
```ruby
|
|
835
|
+
begin
|
|
836
|
+
response = client.board.items_page(
|
|
837
|
+
board_ids: 12345,
|
|
838
|
+
cursor: old_cursor
|
|
839
|
+
)
|
|
840
|
+
rescue Monday::Error => e
|
|
841
|
+
if e.message.include?("cursor")
|
|
842
|
+
puts "Cursor expired. Restarting pagination..."
|
|
843
|
+
cursor = nil
|
|
844
|
+
retry
|
|
845
|
+
end
|
|
846
|
+
end
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### Empty Results
|
|
850
|
+
|
|
851
|
+
**Problem:** Getting empty results when items exist.
|
|
852
|
+
|
|
853
|
+
**Solution:** Check your filter criteria and board ID.
|
|
854
|
+
|
|
855
|
+
```ruby
|
|
856
|
+
response = client.item.page_by_column_values(
|
|
857
|
+
board_id: 12345,
|
|
858
|
+
columns: [
|
|
859
|
+
{
|
|
860
|
+
column_id: "status",
|
|
861
|
+
column_values: ["Done"]
|
|
862
|
+
}
|
|
863
|
+
]
|
|
864
|
+
)
|
|
865
|
+
|
|
866
|
+
items = response.dig("data", "items_page_by_column_values", "items")
|
|
867
|
+
|
|
868
|
+
if items.empty?
|
|
869
|
+
puts "No items match the filter criteria"
|
|
870
|
+
puts "Check:"
|
|
871
|
+
puts " - Board ID is correct"
|
|
872
|
+
puts " - Column ID exists"
|
|
873
|
+
puts " - Column values match exactly"
|
|
874
|
+
end
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
### Rate Limits
|
|
878
|
+
|
|
879
|
+
**Problem:** Hitting API rate limits during pagination.
|
|
880
|
+
|
|
881
|
+
**Solution:** Add delays and implement retry logic.
|
|
882
|
+
|
|
883
|
+
```ruby
|
|
884
|
+
require "monday_ruby"
|
|
885
|
+
|
|
886
|
+
def paginate_with_retry(client, board_id, max_retries: 3)
|
|
887
|
+
all_items = []
|
|
888
|
+
cursor = nil
|
|
889
|
+
retry_count = 0
|
|
890
|
+
|
|
891
|
+
loop do
|
|
892
|
+
begin
|
|
893
|
+
response = client.board.items_page(
|
|
894
|
+
board_ids: board_id,
|
|
895
|
+
limit: 100,
|
|
896
|
+
cursor: cursor
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
items_page = response.dig("data", "boards", 0, "items_page")
|
|
900
|
+
all_items.concat(items_page["items"])
|
|
901
|
+
cursor = items_page["cursor"]
|
|
902
|
+
retry_count = 0
|
|
903
|
+
|
|
904
|
+
break if cursor.nil?
|
|
905
|
+
|
|
906
|
+
sleep(0.5) # Rate limit protection
|
|
907
|
+
|
|
908
|
+
rescue Monday::ComplexityException => e
|
|
909
|
+
if retry_count < max_retries
|
|
910
|
+
retry_count += 1
|
|
911
|
+
wait_time = 60 * retry_count
|
|
912
|
+
puts "Rate limited. Waiting #{wait_time}s..."
|
|
913
|
+
sleep(wait_time)
|
|
914
|
+
retry
|
|
915
|
+
else
|
|
916
|
+
puts "Max retries exceeded"
|
|
917
|
+
break
|
|
918
|
+
end
|
|
919
|
+
end
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
all_items
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
client = Monday::Client.new(token: "your_api_token")
|
|
926
|
+
items = paginate_with_retry(client, 12345)
|
|
927
|
+
puts "Retrieved #{items.length} items"
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
## Next Steps
|
|
931
|
+
|
|
932
|
+
- Learn about [Error Handling](./errors) for robust pagination
|
|
933
|
+
- Explore [Performance Optimization](/explanation/best-practices/performance) for better query performance
|
|
934
|
+
- Check out [Batch Operations](./batch) for processing paginated data
|