0
# JSON Collections
1
2
High-level document store interface for managing JSON documents with querying, filtering, and schema support. Collections provide a NoSQL document database interface built on top of UnQLite's Jx9 scripting engine.
3
4
## Capabilities
5
6
### Collection Management
7
8
Create and manage JSON document collections.
9
10
```python { .api }
11
def collection(self, name):
12
"""Create a wrapper for working with Jx9 collections.
13
Returns Collection object."""
14
...
15
16
class Collection:
17
def __init__(self, unqlite, name):
18
"""Initialize collection with database and collection name."""
19
...
20
21
def create(self):
22
"""Create the named collection. Returns True if created, False if exists."""
23
...
24
25
def drop(self):
26
"""Drop the collection and all associated records. Returns True if dropped."""
27
...
28
29
def exists(self):
30
"""Return boolean indicating whether the collection exists."""
31
...
32
```
33
34
**Usage Example:**
35
36
```python
37
db = unqlite.UnQLite('documents.db')
38
39
# Create collection wrapper
40
users = db.collection('users')
41
42
# Create collection if it doesn't exist
43
if not users.exists():
44
users.create()
45
print("Users collection created")
46
47
# Work with collection
48
print(f"Collection exists: {users.exists()}")
49
50
# Drop collection when done
51
# users.drop()
52
```
53
54
### Document Storage and Retrieval
55
56
Store, fetch, update, and delete JSON documents.
57
58
```python { .api }
59
def store(self, record, return_id=True):
60
"""Create a new JSON document in the collection.
61
Returns record ID if return_id=True, otherwise returns boolean."""
62
...
63
64
def fetch(self, record_id):
65
"""Fetch the document associated with the given ID."""
66
...
67
68
def update(self, record_id, record):
69
"""Update the record identified by the given ID."""
70
...
71
72
def delete(self, record_id):
73
"""Delete the document associated with the given ID."""
74
...
75
76
def all(self):
77
"""Retrieve all records in the given collection."""
78
...
79
```
80
81
**Usage Example:**
82
83
```python
84
db = unqlite.UnQLite('blog.db')
85
posts = db.collection('posts')
86
87
if not posts.exists():
88
posts.create()
89
90
# Store new documents
91
post1_id = posts.store({
92
'title': 'Getting Started with UnQLite',
93
'content': 'UnQLite is a lightweight NoSQL database...',
94
'author': 'Alice',
95
'tags': ['database', 'nosql', 'tutorial'],
96
'published': True
97
})
98
print(f"Created post with ID: {post1_id}")
99
100
post2_id = posts.store({
101
'title': 'Advanced Database Techniques',
102
'content': 'Learn advanced patterns for database design...',
103
'author': 'Bob',
104
'tags': ['database', 'advanced'],
105
'published': False
106
})
107
108
# Fetch specific document
109
post = posts.fetch(post1_id)
110
print(f"Retrieved post: {post['title']}")
111
112
# Update document
113
posts.update(post1_id, {
114
'title': 'Getting Started with UnQLite (Updated)',
115
'content': post['content'] + ' Updated with new examples.',
116
'author': 'Alice',
117
'tags': ['database', 'nosql', 'tutorial', 'updated'],
118
'published': True
119
})
120
121
# Get all documents
122
all_posts = posts.all()
123
print(f"Total posts: {len(all_posts)}")
124
125
# Delete document
126
posts.delete(post2_id)
127
```
128
129
### Dictionary-Style Interface
130
131
Access documents using dictionary-like syntax.
132
133
```python { .api }
134
def __getitem__(self, record_id):
135
"""Fetch document using collection[record_id] syntax."""
136
...
137
138
def __setitem__(self, record_id, record):
139
"""Update document using collection[record_id] = record syntax."""
140
...
141
142
def __delitem__(self, record_id):
143
"""Delete document using del collection[record_id] syntax."""
144
...
145
146
def __len__(self):
147
"""Return the number of records in the document collection."""
148
...
149
```
150
151
**Usage Example:**
152
153
```python
154
db = unqlite.UnQLite(':mem:')
155
products = db.collection('products')
156
products.create()
157
158
# Store initial document
159
product_id = products.store({
160
'name': 'Laptop',
161
'price': 999.99,
162
'category': 'electronics',
163
'in_stock': True
164
})
165
166
# Dictionary-style access
167
product = products[product_id]
168
print(f"Product: {product['name']}")
169
170
# Dictionary-style update
171
products[product_id] = {
172
'name': 'Gaming Laptop',
173
'price': 1299.99,
174
'category': 'electronics',
175
'in_stock': True,
176
'features': ['RGB lighting', 'High refresh rate']
177
}
178
179
# Check collection size
180
print(f"Products in collection: {len(products)}")
181
182
# Dictionary-style deletion
183
del products[product_id]
184
print(f"Products after deletion: {len(products)}")
185
```
186
187
### Document Querying and Filtering
188
189
Filter documents using Python callback functions.
190
191
```python { .api }
192
def filter(self, filter_fn):
193
"""Filter the records in the collection using the provided Python callback.
194
Returns list of matching documents."""
195
...
196
```
197
198
**Usage Example:**
199
200
```python
201
db = unqlite.UnQLite(':mem:')
202
employees = db.collection('employees')
203
employees.create()
204
205
# Add sample data
206
sample_employees = [
207
{'name': 'Alice', 'department': 'Engineering', 'salary': 85000, 'active': True},
208
{'name': 'Bob', 'department': 'Marketing', 'salary': 65000, 'active': True},
209
{'name': 'Charlie', 'department': 'Engineering', 'salary': 95000, 'active': False},
210
{'name': 'Diana', 'department': 'Sales', 'salary': 70000, 'active': True},
211
{'name': 'Eve', 'department': 'Engineering', 'salary': 90000, 'active': True}
212
]
213
214
for emp in sample_employees:
215
employees.store(emp)
216
217
# Filter by department
218
def is_engineer(employee):
219
return employee.get('department') == 'Engineering'
220
221
engineers = employees.filter(is_engineer)
222
print(f"Engineers: {len(engineers)}")
223
for eng in engineers:
224
print(f" {eng['name']}: ${eng['salary']}")
225
226
# Filter by salary and status
227
def high_earning_active(employee):
228
return employee.get('salary', 0) > 80000 and employee.get('active', False)
229
230
high_earners = employees.filter(high_earning_active)
231
print(f"High-earning active employees: {len(high_earners)}")
232
233
# Complex filter with multiple conditions
234
def senior_engineer(employee):
235
return (employee.get('department') == 'Engineering' and
236
employee.get('salary', 0) > 90000 and
237
employee.get('active', False))
238
239
senior_engineers = employees.filter(senior_engineer)
240
print(f"Senior engineers: {len(senior_engineers)}")
241
```
242
243
### Schema Management
244
245
Define and manage document schemas for data validation.
246
247
```python { .api }
248
def set_schema(self, _schema=None, **kwargs):
249
"""Set collection schema for document validation."""
250
...
251
252
def get_schema(self):
253
"""Get the current collection schema."""
254
...
255
```
256
257
**Usage Example:**
258
259
```python
260
db = unqlite.UnQLite('structured.db')
261
users = db.collection('users')
262
users.create()
263
264
# Define schema
265
user_schema = {
266
'name': {'type': 'string', 'required': True},
267
'email': {'type': 'string', 'required': True},
268
'age': {'type': 'number', 'required': False},
269
'active': {'type': 'boolean', 'default': True}
270
}
271
272
# Set schema
273
users.set_schema(user_schema)
274
275
# Alternative syntax using kwargs
276
users.set_schema(
277
name={'type': 'string', 'required': True},
278
email={'type': 'string', 'required': True}
279
)
280
281
# Retrieve schema
282
current_schema = users.get_schema()
283
print(f"Current schema: {current_schema}")
284
285
# Store documents (schema validation depends on UnQLite/Jx9 implementation)
286
try:
287
user_id = users.store({
288
'name': 'Alice Johnson',
289
'email': 'alice@example.com',
290
'age': 30
291
})
292
print(f"User stored with ID: {user_id}")
293
except Exception as e:
294
print(f"Schema validation failed: {e}")
295
```
296
297
### Collection Metadata
298
299
Access collection metadata and status information.
300
301
```python { .api }
302
def last_record_id(self):
303
"""Return the ID of the last document to be stored."""
304
...
305
306
def current_record_id(self):
307
"""Return the ID of the current JSON document."""
308
...
309
310
def creation_date(self):
311
"""Return collection creation date."""
312
...
313
314
def error_log(self):
315
"""Return collection error log."""
316
...
317
```
318
319
**Usage Example:**
320
321
```python
322
db = unqlite.UnQLite('metadata.db')
323
logs = db.collection('logs')
324
logs.create()
325
326
# Store some documents
327
log1_id = logs.store({'level': 'info', 'message': 'Application started'})
328
log2_id = logs.store({'level': 'warning', 'message': 'Low disk space'})
329
log3_id = logs.store({'level': 'error', 'message': 'Database connection failed'})
330
331
# Get metadata
332
print(f"Last record ID: {logs.last_record_id()}")
333
print(f"Current record ID: {logs.current_record_id()}")
334
print(f"Creation date: {logs.creation_date()}")
335
336
# Check for errors
337
error_log = logs.error_log()
338
if error_log:
339
print(f"Errors: {error_log}")
340
```
341
342
### Cursor Operations
343
344
Navigate through collection documents with cursor-like operations.
345
346
```python { .api }
347
def fetch_current(self):
348
"""Return current document at cursor position."""
349
...
350
351
def reset_cursor(self):
352
"""Reset collection cursor to beginning."""
353
...
354
```
355
356
**Usage Example:**
357
358
```python
359
db = unqlite.UnQLite(':mem:')
360
news = db.collection('news')
361
news.create()
362
363
# Add articles
364
articles = [
365
{'headline': 'Tech News Update', 'category': 'technology'},
366
{'headline': 'Sports Results', 'category': 'sports'},
367
{'headline': 'Weather Forecast', 'category': 'weather'}
368
]
369
370
for article in articles:
371
news.store(article)
372
373
# Reset cursor and fetch current
374
news.reset_cursor()
375
current = news.fetch_current()
376
if current:
377
print(f"Current article: {current['headline']}")
378
```
379
380
### Collection Iteration
381
382
Iterate through all documents in a collection.
383
384
```python { .api }
385
def iterator(self):
386
"""Return CollectionIterator object."""
387
...
388
389
def __iter__(self):
390
"""Return iterator for collection documents."""
391
...
392
393
class CollectionIterator:
394
def __iter__(self):
395
"""Setup iteration."""
396
...
397
398
def __next__(self):
399
"""Get next document. Raises StopIteration at end."""
400
...
401
```
402
403
**Usage Example:**
404
405
```python
406
db = unqlite.UnQLite(':mem:')
407
tasks = db.collection('tasks')
408
tasks.create()
409
410
# Add tasks
411
task_data = [
412
{'title': 'Write documentation', 'priority': 'high', 'completed': False},
413
{'title': 'Review code', 'priority': 'medium', 'completed': True},
414
{'title': 'Deploy application', 'priority': 'high', 'completed': False},
415
{'title': 'Update dependencies', 'priority': 'low', 'completed': False}
416
]
417
418
for task in task_data:
419
tasks.store(task)
420
421
# Iterate through all tasks
422
print("All tasks:")
423
for task in tasks:
424
status = "✓" if task['completed'] else "○"
425
print(f" {status} {task['title']} ({task['priority']})")
426
427
# Use explicit iterator
428
print("High-priority tasks:")
429
task_iter = tasks.iterator()
430
for task in task_iter:
431
if task['priority'] == 'high':
432
print(f" {task['title']}")
433
```
434
435
## Advanced Usage
436
437
### Complex Document Structures
438
439
Work with nested documents and complex data structures:
440
441
```python
442
db = unqlite.UnQLite('complex.db')
443
orders = db.collection('orders')
444
orders.create()
445
446
# Complex nested document
447
order = {
448
'order_id': 'ORD-2024-001',
449
'customer': {
450
'name': 'Alice Johnson',
451
'email': 'alice@example.com',
452
'address': {
453
'street': '123 Main St',
454
'city': 'Anytown',
455
'zip': '12345'
456
}
457
},
458
'items': [
459
{'product': 'Laptop', 'quantity': 1, 'price': 999.99},
460
{'product': 'Mouse', 'quantity': 2, 'price': 29.99}
461
],
462
'total': 1059.97,
463
'status': 'pending',
464
'created_at': '2024-01-15T10:30:00Z'
465
}
466
467
order_id = orders.store(order)
468
469
# Filter by nested properties
470
def high_value_orders(order):
471
return order.get('total', 0) > 500
472
473
valuable_orders = orders.filter(high_value_orders)
474
print(f"High-value orders: {len(valuable_orders)}")
475
```
476
477
### Bulk Operations
478
479
Efficiently handle multiple documents:
480
481
```python
482
db = unqlite.UnQLite('bulk.db')
483
inventory = db.collection('inventory')
484
inventory.create()
485
486
# Bulk insert
487
products = [
488
{'sku': 'LAPTOP-001', 'name': 'Gaming Laptop', 'stock': 25},
489
{'sku': 'MOUSE-001', 'name': 'Wireless Mouse', 'stock': 100},
490
{'sku': 'KEYBOARD-001', 'name': 'Mechanical Keyboard', 'stock': 50}
491
]
492
493
# Store all products
494
product_ids = []
495
for product in products:
496
product_id = inventory.store(product, return_id=True)
497
product_ids.append(product_id)
498
499
print(f"Stored {len(product_ids)} products")
500
501
# Bulk update using filter
502
def needs_restock(item):
503
return item.get('stock', 0) < 30
504
505
low_stock_items = inventory.filter(needs_restock)
506
print(f"Items needing restock: {len(low_stock_items)}")
507
508
# Update low stock items
509
for item in low_stock_items:
510
# Note: This requires knowing the record ID
511
# In practice, you'd need to track IDs or use custom logic
512
updated_item = item.copy()
513
updated_item['status'] = 'reorder_needed'
514
# inventory.update(item_id, updated_item)
515
```
516
517
## Performance Considerations
518
519
- **Use appropriate indexing**: While not directly exposed, UnQLite/Jx9 may benefit from proper key design
520
- **Minimize filter complexity**: Complex Python callbacks can be slow for large collections
521
- **Batch operations**: Group related operations when possible
522
- **Consider pagination**: For large result sets, implement pagination patterns
523
524
```python
525
# Efficient: Simple filter conditions
526
def active_users(user):
527
return user.get('active', False)
528
529
# Less efficient: Complex calculations in filter
530
def complex_scoring(user):
531
score = sum(user.get('metrics', {}).values()) * 0.8
532
return score > calculate_threshold(user.get('category'))
533
534
# Better: Pre-calculate and store scores
535
def pre_calculated_filter(user):
536
return user.get('precalculated_score', 0) > user.get('threshold', 0)
537
```