monday_ruby 1.1.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -1
  3. data/.rubocop.yml +2 -1
  4. data/CHANGELOG.md +14 -0
  5. data/CONTRIBUTING.md +104 -0
  6. data/README.md +146 -142
  7. data/docs/.vitepress/config.mjs +255 -0
  8. data/docs/.vitepress/theme/index.js +4 -0
  9. data/docs/.vitepress/theme/style.css +43 -0
  10. data/docs/README.md +80 -0
  11. data/docs/explanation/architecture.md +507 -0
  12. data/docs/explanation/best-practices/errors.md +478 -0
  13. data/docs/explanation/best-practices/performance.md +1084 -0
  14. data/docs/explanation/best-practices/rate-limiting.md +630 -0
  15. data/docs/explanation/best-practices/testing.md +820 -0
  16. data/docs/explanation/column-values.md +857 -0
  17. data/docs/explanation/design.md +795 -0
  18. data/docs/explanation/graphql.md +356 -0
  19. data/docs/explanation/migration/v1.md +808 -0
  20. data/docs/explanation/pagination.md +447 -0
  21. data/docs/guides/advanced/batch.md +1274 -0
  22. data/docs/guides/advanced/complex-queries.md +1114 -0
  23. data/docs/guides/advanced/errors.md +818 -0
  24. data/docs/guides/advanced/pagination.md +934 -0
  25. data/docs/guides/advanced/rate-limiting.md +981 -0
  26. data/docs/guides/authentication.md +286 -0
  27. data/docs/guides/boards/create.md +386 -0
  28. data/docs/guides/boards/delete.md +405 -0
  29. data/docs/guides/boards/duplicate.md +511 -0
  30. data/docs/guides/boards/query.md +530 -0
  31. data/docs/guides/boards/update.md +453 -0
  32. data/docs/guides/columns/create.md +452 -0
  33. data/docs/guides/columns/metadata.md +492 -0
  34. data/docs/guides/columns/query.md +455 -0
  35. data/docs/guides/columns/update-multiple.md +459 -0
  36. data/docs/guides/columns/update-values.md +509 -0
  37. data/docs/guides/files/add-to-column.md +40 -0
  38. data/docs/guides/files/add-to-update.md +37 -0
  39. data/docs/guides/files/clear-column.md +33 -0
  40. data/docs/guides/first-request.md +285 -0
  41. data/docs/guides/folders/manage.md +750 -0
  42. data/docs/guides/groups/items.md +626 -0
  43. data/docs/guides/groups/manage.md +501 -0
  44. data/docs/guides/installation.md +169 -0
  45. data/docs/guides/items/create.md +493 -0
  46. data/docs/guides/items/delete.md +514 -0
  47. data/docs/guides/items/query.md +605 -0
  48. data/docs/guides/items/subitems.md +483 -0
  49. data/docs/guides/items/update.md +699 -0
  50. data/docs/guides/updates/manage.md +619 -0
  51. data/docs/guides/use-cases/dashboard.md +1421 -0
  52. data/docs/guides/use-cases/import.md +1962 -0
  53. data/docs/guides/use-cases/task-management.md +1381 -0
  54. data/docs/guides/workspaces/manage.md +502 -0
  55. data/docs/index.md +69 -0
  56. data/docs/package-lock.json +2468 -0
  57. data/docs/package.json +13 -0
  58. data/docs/reference/client.md +540 -0
  59. data/docs/reference/configuration.md +586 -0
  60. data/docs/reference/errors.md +693 -0
  61. data/docs/reference/resources/account.md +208 -0
  62. data/docs/reference/resources/activity-log.md +369 -0
  63. data/docs/reference/resources/board-view.md +359 -0
  64. data/docs/reference/resources/board.md +393 -0
  65. data/docs/reference/resources/column.md +543 -0
  66. data/docs/reference/resources/file.md +236 -0
  67. data/docs/reference/resources/folder.md +386 -0
  68. data/docs/reference/resources/group.md +507 -0
  69. data/docs/reference/resources/item.md +348 -0
  70. data/docs/reference/resources/subitem.md +267 -0
  71. data/docs/reference/resources/update.md +259 -0
  72. data/docs/reference/resources/workspace.md +213 -0
  73. data/docs/reference/response.md +560 -0
  74. data/docs/tutorial/first-integration.md +713 -0
  75. data/lib/monday/client.rb +24 -0
  76. data/lib/monday/configuration.rb +5 -0
  77. data/lib/monday/request.rb +15 -0
  78. data/lib/monday/resources/base.rb +4 -0
  79. data/lib/monday/resources/file.rb +56 -0
  80. data/lib/monday/util.rb +1 -0
  81. data/lib/monday/version.rb +1 -1
  82. metadata +87 -4
@@ -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