interaqt 0.3.0 → 0.3.1

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 (35) hide show
  1. package/agent/.claude/agents/code-generation-handler.md +2 -0
  2. package/agent/.claude/agents/computation-generation-handler.md +1 -0
  3. package/agent/.claude/agents/implement-design-handler.md +4 -13
  4. package/agent/.claude/agents/requirements-analysis-handler.md +46 -14
  5. package/agent/agentspace/knowledge/generator/api-reference.md +3378 -0
  6. package/agent/agentspace/knowledge/generator/basic-interaction-generation.md +377 -0
  7. package/agent/agentspace/knowledge/generator/computation-analysis.md +307 -0
  8. package/agent/agentspace/knowledge/generator/computation-implementation.md +959 -0
  9. package/agent/agentspace/knowledge/generator/data-analysis.md +463 -0
  10. package/agent/agentspace/knowledge/generator/entity-relation-generation.md +395 -0
  11. package/agent/agentspace/knowledge/generator/permission-implementation.md +460 -0
  12. package/agent/agentspace/knowledge/generator/permission-test-implementation.md +870 -0
  13. package/agent/agentspace/knowledge/generator/test-implementation.md +674 -0
  14. package/agent/agentspace/knowledge/usage/00-mindset-shift.md +322 -0
  15. package/agent/agentspace/knowledge/usage/01-core-concepts.md +131 -0
  16. package/agent/agentspace/knowledge/usage/02-define-entities-properties.md +407 -0
  17. package/agent/agentspace/knowledge/usage/03-entity-relations.md +599 -0
  18. package/agent/agentspace/knowledge/usage/04-reactive-computations.md +2186 -0
  19. package/agent/agentspace/knowledge/usage/05-interactions.md +1411 -0
  20. package/agent/agentspace/knowledge/usage/06-attributive-permissions.md +10 -0
  21. package/agent/agentspace/knowledge/usage/07-payload-parameters.md +593 -0
  22. package/agent/agentspace/knowledge/usage/08-activities.md +863 -0
  23. package/agent/agentspace/knowledge/usage/09-filtered-entities.md +784 -0
  24. package/agent/agentspace/knowledge/usage/10-async-computations.md +734 -0
  25. package/agent/agentspace/knowledge/usage/11-global-dictionaries.md +942 -0
  26. package/agent/agentspace/knowledge/usage/12-data-querying.md +1033 -0
  27. package/agent/agentspace/knowledge/usage/13-testing.md +1201 -0
  28. package/agent/agentspace/knowledge/usage/14-api-reference.md +1606 -0
  29. package/agent/agentspace/knowledge/usage/15-entity-crud-patterns.md +1122 -0
  30. package/agent/agentspace/knowledge/usage/16-frontend-page-design-guide.md +485 -0
  31. package/agent/agentspace/knowledge/usage/17-performance-optimization.md +283 -0
  32. package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +176 -0
  33. package/agent/agentspace/knowledge/usage/19-common-anti-patterns.md +563 -0
  34. package/agent/agentspace/knowledge/usage/README.md +148 -0
  35. package/package.json +1 -1
@@ -0,0 +1,784 @@
1
+ # How to Use Filtered Entities
2
+
3
+ Filtered Entity is an advanced feature in interaqt that allows you to create entity views based on specific conditions. A filtered entity is like a subset of the original entity, containing only records that meet certain conditions, while supporting reactive computations on this subset.
4
+
5
+ ## Understanding Filtered Entities
6
+
7
+ ### What is a Filtered Entity
8
+
9
+ A filtered entity is a virtual view created based on an existing entity, which:
10
+ - **Filters based on conditions**: Only contains records that meet specific conditions
11
+ - **Real-time updates**: Automatically updates when original data changes
12
+ - **Supports computations**: Can perform reactive computations on filtered data
13
+ - **Maintains references**: Records in filtered entities are still references to original entity records
14
+
15
+ ### Use Cases
16
+
17
+ Filtered entities are particularly suitable for the following scenarios:
18
+ - **Status grouping**: Such as published posts, active users, pending orders
19
+ - **Permission control**: Such as users can only see their own data
20
+ - **Category statistics**: Such as counting products by category
21
+ - **Conditional aggregation**: Such as calculating sums or averages under specific conditions
22
+
23
+ ### Filtered Entity vs Regular Queries
24
+
25
+ ```javascript
26
+ // Regular query approach: Re-query every time
27
+ const getPublishedPosts = async () => {
28
+ return await controller.find('Post', { status: 'published' });
29
+ };
30
+
31
+ const getPublishedPostCount = async () => {
32
+ return await controller.count('Post', { status: 'published' });
33
+ };
34
+
35
+ // Filtered entity approach: Automatically maintained, reactive updates
36
+ const PublishedPost = Entity.create({
37
+ name: 'PublishedPost',
38
+ baseEntity: Post,
39
+ filterCondition: MatchExp.atom({
40
+ key: 'status',
41
+ value: ['=', 'published']
42
+ })
43
+ });
44
+
45
+ // Automatically maintained count
46
+ const GlobalStats = Entity.create({
47
+ name: 'GlobalStats',
48
+ properties: [
49
+ Property.create({
50
+ name: 'publishedPostCount',
51
+ type: 'number',
52
+ defaultValue: () => 0,
53
+ computation: Count.create({
54
+ record: PublishedPost
55
+ }) // Automatically updates
56
+ })
57
+ ]
58
+ });
59
+ ```
60
+
61
+ ## Creating Filtered Entities
62
+
63
+ ### Filtering Based on Properties
64
+
65
+ ```javascript
66
+ import { FilteredEntity, Entity, Property } from 'interaqt';
67
+
68
+ // Original entity
69
+ const Post = Entity.create({
70
+ name: 'Post',
71
+ properties: [
72
+ Property.create({ name: 'title', type: 'string' }),
73
+ Property.create({ name: 'content', type: 'string' }),
74
+ Property.create({ name: 'status', type: 'string' }),
75
+ Property.create({ name: 'category', type: 'string' }),
76
+ Property.create({ name: 'publishedAt', type: 'string' }),
77
+ Property.create({ name: 'viewCount', type: 'number', defaultValue: 0 })
78
+ ]
79
+ });
80
+
81
+ // Create filtered entity for published posts
82
+ const PublishedPost = Entity.create({
83
+ name: 'PublishedPost',
84
+ baseEntity: Post,
85
+ filterCondition: MatchExp.atom({
86
+ key: 'status',
87
+ value: ['=', 'published']
88
+ })
89
+ });
90
+
91
+ // Create filtered entity for popular posts
92
+ const PopularPost = Entity.create({
93
+ name: 'PopularPost',
94
+ baseEntity: Post,
95
+ filterCondition: MatchExp.atom({
96
+ key: 'status',
97
+ value: ['=', 'published']
98
+ }).and({
99
+ key: 'viewCount',
100
+ value: ['>=', 1000]
101
+ })
102
+ });
103
+
104
+ // Create filtered entity for tech posts
105
+ const TechPost = Entity.create({
106
+ name: 'TechPost',
107
+ baseEntity: Post,
108
+ filterCondition: MatchExp.atom({
109
+ key: 'category',
110
+ value: ['=', 'technology']
111
+ }).and({
112
+ key: 'status',
113
+ value: ['=', 'published']
114
+ })
115
+ });
116
+ ```
117
+
118
+ ### Filtering Based on Relations
119
+
120
+ ```javascript
121
+ const User = Entity.create({
122
+ name: 'User',
123
+ properties: [
124
+ Property.create({ name: 'name', type: 'string' }),
125
+ Property.create({ name: 'email', type: 'string' }),
126
+ Property.create({ name: 'status', type: 'string' }),
127
+ Property.create({ name: 'lastLoginAt', type: 'string' })
128
+ ]
129
+ });
130
+
131
+ const UserPost = Relation.create({
132
+ source: User,
133
+ sourceProperty: 'posts',
134
+ target: Post,
135
+ targetProperty: 'author',
136
+ type: '1:n'
137
+ });
138
+
139
+ // Create filtered entity for active users (logged in within the last 30 days)
140
+ const ActiveUser = Entity.create({
141
+ name: 'ActiveUser',
142
+ baseEntity: User,
143
+ filterCondition: MatchExp.atom({
144
+ key: 'status',
145
+ value: ['=', 'active']
146
+ }).and({
147
+ key: 'lastLoginAt',
148
+ value: ['>=', (() => {
149
+ const thirtyDaysAgo = new Date();
150
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
151
+ return thirtyDaysAgo.toISOString();
152
+ })()]
153
+ })
154
+ });
155
+
156
+ // Create filtered entity for users with posts (needs to be implemented through relation queries)
157
+ const AuthorUser = Entity.create({
158
+ name: 'AuthorUser',
159
+ baseEntity: User,
160
+ filterCondition: MatchExp.atom({
161
+ key: 'id',
162
+ value: ['in', 'SELECT DISTINCT author FROM Post WHERE author IS NOT NULL']
163
+ })
164
+ });
165
+ ```
166
+
167
+ ### Dynamic Filter Conditions
168
+
169
+ ```javascript
170
+ // Use functions as filter conditions, supporting dynamic computation
171
+ const RecentPost = FilteredEntity.create({
172
+ name: 'RecentPost',
173
+ baseEntity: Post,
174
+ filter: () => {
175
+ const sevenDaysAgo = new Date();
176
+ sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
177
+
178
+ return {
179
+ status: 'published',
180
+ publishedAt: { $gte: sevenDaysAgo.toISOString() }
181
+ };
182
+ }
183
+ });
184
+
185
+ // Context-based filtering (such as user permissions)
186
+ const createUserVisiblePosts = (userId) => {
187
+ return FilteredEntity.create({
188
+ name: `UserVisiblePosts_${userId}`,
189
+ baseEntity: Post,
190
+ filter: async (context) => {
191
+ const user = await context.findOne('User', { id: userId });
192
+
193
+ if (user.role === 'admin') {
194
+ // Admins can see all posts
195
+ return {};
196
+ }
197
+
198
+ if (user.role === 'moderator') {
199
+ // Moderators can see published and pending review posts
200
+ return {
201
+ status: { $in: ['published', 'pending_review'] }
202
+ };
203
+ }
204
+
205
+ // Regular users can only see published posts
206
+ return {
207
+ status: 'published'
208
+ };
209
+ }
210
+ });
211
+ };
212
+ ```
213
+
214
+ ### Complex Filter Conditions
215
+
216
+ ```javascript
217
+ // Use complex query conditions
218
+ const AdvancedFilteredPost = FilteredEntity.create({
219
+ name: 'AdvancedFilteredPost',
220
+ baseEntity: Post,
221
+ filter: {
222
+ $and: [
223
+ { status: 'published' },
224
+ {
225
+ $or: [
226
+ { category: 'technology' },
227
+ { category: 'science' }
228
+ ]
229
+ },
230
+ {
231
+ $expr: {
232
+ $gt: [
233
+ '$viewCount',
234
+ { $multiply: ['$likeCount', 10] }
235
+ ]
236
+ }
237
+ }
238
+ ]
239
+ }
240
+ });
241
+
242
+ // Date range-based filtering
243
+ const MonthlyPost = FilteredEntity.create({
244
+ name: 'MonthlyPost',
245
+ baseEntity: Post,
246
+ filter: (context) => {
247
+ const now = new Date();
248
+ const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
249
+ const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0);
250
+
251
+ return {
252
+ status: 'published',
253
+ publishedAt: {
254
+ $gte: startOfMonth.toISOString(),
255
+ $lte: endOfMonth.toISOString()
256
+ }
257
+ };
258
+ }
259
+ });
260
+ ```
261
+
262
+ ## Operating on Filtered Entities
263
+
264
+ ### Querying Filtered Data
265
+
266
+ ```javascript
267
+ // Query filtered entities just like regular entities
268
+ const publishedPosts = await controller.find('PublishedPost');
269
+ console.log('Published posts:', publishedPosts);
270
+
271
+ // Further filtering on filtered entities
272
+ const recentPublishedPosts = await controller.find('PublishedPost', {
273
+ publishedAt: {
274
+ $gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()
275
+ }
276
+ });
277
+
278
+ // Query single record
279
+ const firstPublishedPost = await controller.findOne('PublishedPost', {
280
+ category: 'technology'
281
+ });
282
+
283
+ // Count query
284
+ const publishedPostCount = await controller.count('PublishedPost');
285
+ ```
286
+
287
+ ### Updating Filtered Data
288
+
289
+ ```javascript
290
+ // Update records in filtered entities
291
+ await controller.update('PublishedPost',
292
+ { category: 'technology' },
293
+ {
294
+ updatedAt: new Date().toISOString(),
295
+ tags: ['tech', 'programming']
296
+ }
297
+ );
298
+
299
+ // Batch update
300
+ await controller.updateMany('PublishedPost',
301
+ { viewCount: { $lt: 100 } },
302
+ {
303
+ $inc: { viewCount: 10 } // Add 10 views to low-view posts
304
+ }
305
+ );
306
+
307
+ // Update single record
308
+ const post = await controller.findOne('PublishedPost', { id: 'post123' });
309
+ if (post) {
310
+ await controller.update('PublishedPost',
311
+ { id: post.id },
312
+ {
313
+ title: 'Updated Title',
314
+ content: 'Updated Content'
315
+ }
316
+ );
317
+ }
318
+ ```
319
+
320
+ ### Deleting Filtered Data
321
+
322
+ ```javascript
323
+ // Delete records in filtered entities
324
+ await controller.delete('PublishedPost', {
325
+ category: 'outdated',
326
+ publishedAt: {
327
+ $lt: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString() // Outdated content from a year ago
328
+ }
329
+ });
330
+
331
+ // Soft delete (update status instead of actual deletion)
332
+ await controller.update('PublishedPost',
333
+ { id: 'post123' },
334
+ { status: 'archived' } // This will cause the record to disappear from PublishedPost
335
+ );
336
+ ```
337
+
338
+ ## Filtered Entities and Reactive Computations
339
+
340
+ ### Using Filtered Entities in Computations
341
+
342
+ ```javascript
343
+ // Use filtered entities for computations
344
+ const User = Entity.create({
345
+ name: 'User',
346
+ properties: [
347
+ Property.create({ name: 'name', type: 'string' }),
348
+
349
+ // Calculate the number of published posts by user
350
+ Property.create({
351
+ name: 'publishedPostCount',
352
+ type: 'number',
353
+ defaultValue: () => 0,
354
+ computation: Count.create({
355
+ record: UserPublishedPosts
356
+ })
357
+ }),
358
+
359
+ // Calculate the number of popular posts by user
360
+ Property.create({
361
+ name: 'popularPostCount',
362
+ type: 'number',
363
+ defaultValue: () => 0,
364
+ computation: Count.create({
365
+ record: UserPopularPosts
366
+ })
367
+ }),
368
+
369
+ // Calculate total views of user's posts
370
+ Property.create({
371
+ name: 'totalViews',
372
+ type: 'number',
373
+ defaultValue: () => 0,
374
+ computation: WeightedSummation.create({
375
+ record: UserPublishedPosts,
376
+ callback: (relation) => ({
377
+ weight: 1,
378
+ value: relation.target.viewCount
379
+ })
380
+ })
381
+ }),
382
+
383
+ // Calculate if user is an active author
384
+ Property.create({
385
+ name: 'isActiveAuthor',
386
+ type: 'boolean',
387
+ defaultValue: () => false,
388
+ computed: function(user) {
389
+ // Assuming user has a recentPosts property that's an array
390
+ const recentPosts = user.recentPosts || [];
391
+ return recentPosts.length >= 3; // Has 3 or more recent posts
392
+ }
393
+ })
394
+ ]
395
+ });
396
+ ```
397
+
398
+ ### Global Statistics Computation
399
+
400
+ ```javascript
401
+ const GlobalStats = Entity.create({
402
+ name: 'GlobalStats',
403
+ properties: [
404
+ // Various post statistics
405
+ Property.create({
406
+ name: 'totalPublishedPosts',
407
+ type: 'number',
408
+ defaultValue: () => 0,
409
+ computation: Count.create({
410
+ record: PublishedPost
411
+ })
412
+ }),
413
+
414
+ Property.create({
415
+ name: 'totalPopularPosts',
416
+ type: 'number',
417
+ defaultValue: () => 0,
418
+ computation: Count.create({
419
+ record: PopularPost
420
+ })
421
+ }),
422
+
423
+ Property.create({
424
+ name: 'totalTechPosts',
425
+ type: 'number',
426
+ defaultValue: () => 0,
427
+ computation: Count.create({
428
+ record: TechPost
429
+ })
430
+ }),
431
+
432
+ // User statistics
433
+ Property.create({
434
+ name: 'activeUserCount',
435
+ type: 'number',
436
+ defaultValue: () => 0,
437
+ computation: Count.create({
438
+ record: ActiveUser
439
+ })
440
+ }),
441
+
442
+ Property.create({
443
+ name: 'authorCount',
444
+ type: 'number',
445
+ defaultValue: () => 0,
446
+ computation: Count.create({
447
+ record: AuthorUser
448
+ })
449
+ }),
450
+
451
+ // Check if all popular posts have tags
452
+ Property.create({
453
+ name: 'allPopularPostsTagged',
454
+ type: 'boolean',
455
+ computation: new Every(PopularPost, null, {
456
+ 'tags.length': { $gt: 0 }
457
+ })
458
+ })
459
+ ]
460
+ });
461
+ ```
462
+
463
+ ### Category Statistics
464
+
465
+ ```javascript
466
+ // Create filtered entities for each category
467
+ const categories = ['technology', 'science', 'business', 'lifestyle'];
468
+
469
+ const categoryEntities = categories.map(category =>
470
+ FilteredEntity.create({
471
+ name: `${category.charAt(0).toUpperCase() + category.slice(1)}Post`,
472
+ baseEntity: Post,
473
+ filter: {
474
+ category: category,
475
+ status: 'published'
476
+ }
477
+ })
478
+ );
479
+
480
+ // Create category statistics entity
481
+ const CategoryStats = Entity.create({
482
+ name: 'CategoryStats',
483
+ properties: [
484
+ ...categories.map(category =>
485
+ Property.create({
486
+ name: `${category}Count`,
487
+ type: 'number',
488
+ computation: new Count(
489
+ categoryEntities.find(e => e.name.toLowerCase().startsWith(category))
490
+ )
491
+ })
492
+ ),
493
+
494
+ // Most popular category
495
+ Property.create({
496
+ name: 'mostPopularCategory',
497
+ type: 'string',
498
+ computation: new Transform(
499
+ categoryEntities,
500
+ null,
501
+ (allCategoryData) => {
502
+ let maxCount = 0;
503
+ let mostPopular = '';
504
+
505
+ categories.forEach(category => {
506
+ const categoryData = allCategoryData.find(data =>
507
+ data.entityName.toLowerCase().startsWith(category)
508
+ );
509
+ if (categoryData && categoryData.count > maxCount) {
510
+ maxCount = categoryData.count;
511
+ mostPopular = category;
512
+ }
513
+ });
514
+
515
+ return mostPopular;
516
+ }
517
+ )
518
+ })
519
+ ]
520
+ });
521
+ ```
522
+
523
+ ## Real-time Updates and Event Handling
524
+
525
+ ### Automatic Update Mechanism
526
+
527
+ ```javascript
528
+ // When original data changes, filtered entities automatically update
529
+ const createPost = async (postData) => {
530
+ // Create new post
531
+ const post = await controller.create('Post', {
532
+ ...postData,
533
+ status: 'draft' // Initial status is draft
534
+ });
535
+
536
+ // At this point, PublishedPost won't include this post
537
+
538
+ // Publish the post
539
+ await controller.update('Post',
540
+ { id: post.id },
541
+ { status: 'published', publishedAt: new Date().toISOString() }
542
+ );
543
+
544
+ // Now PublishedPost will automatically include this post
545
+ // Related computations (like publishedPostCount) will also update automatically
546
+ };
547
+ ```
548
+
549
+ ### Listening to Filtered Entity Changes
550
+
551
+ ```javascript
552
+ // Listen to filtered entity change events
553
+ controller.on('filteredEntityChange', (event) => {
554
+ console.log('Filtered entity change:', {
555
+ entityName: event.entityName,
556
+ changeType: event.changeType, // 'added', 'removed', 'updated'
557
+ recordId: event.recordId,
558
+ oldData: event.oldData,
559
+ newData: event.newData
560
+ });
561
+
562
+ // Custom logic can be executed here
563
+ if (event.entityName === 'PublishedPost' && event.changeType === 'added') {
564
+ // Handle logic when new post is published
565
+ notifySubscribers(event.newData);
566
+ }
567
+ });
568
+
569
+ // Listen to specific filtered entity changes
570
+ controller.on('PublishedPost:added', (post) => {
571
+ console.log('New published post:', post);
572
+ // Send notifications, update cache, etc.
573
+ });
574
+
575
+ controller.on('ActiveUser:removed', (user) => {
576
+ console.log('User became inactive:', user);
577
+ // Handle user inactivity logic
578
+ });
579
+ ```
580
+
581
+ ## Performance Optimization
582
+
583
+ ### Index Optimization
584
+
585
+ ```javascript
586
+ // Add indexes for fields used in filter conditions
587
+ const OptimizedPost = Entity.create({
588
+ name: 'Post',
589
+ properties: [
590
+ Property.create({
591
+ name: 'status',
592
+ type: 'string',
593
+ index: true // Add index for status field
594
+ }),
595
+ Property.create({
596
+ name: 'category',
597
+ type: 'string',
598
+ index: true // Add index for category field
599
+ }),
600
+ Property.create({
601
+ name: 'publishedAt',
602
+ type: 'string',
603
+ index: true // Add index for published time
604
+ }),
605
+ Property.create({
606
+ name: 'viewCount',
607
+ type: 'number',
608
+ index: true // Add index for view count
609
+ })
610
+ ]
611
+ });
612
+
613
+ // Composite indexes
614
+ const PostWithCompositeIndex = Entity.create({
615
+ name: 'Post',
616
+ properties: [
617
+ // ... other properties
618
+ ],
619
+ indexes: [
620
+ { fields: ['status', 'category'] }, // Composite index
621
+ { fields: ['status', 'publishedAt'] },
622
+ { fields: ['category', 'viewCount'] }
623
+ ]
624
+ });
625
+ ```
626
+
627
+ ### Caching Strategy
628
+
629
+ ```javascript
630
+ // Configure caching strategy for filtered entities
631
+ const CachedFilteredEntity = FilteredEntity.create({
632
+ name: 'CachedPublishedPost',
633
+ baseEntity: Post,
634
+ filter: { status: 'published' },
635
+ cache: {
636
+ enabled: true,
637
+ ttl: 300, // Cache for 5 minutes
638
+ invalidateOnChange: true // Automatically invalidate cache on data changes
639
+ }
640
+ });
641
+ ```
642
+
643
+ ### Pagination and Limits
644
+
645
+ ```javascript
646
+ // Use pagination when querying filtered entities
647
+ const getPublishedPostsPaginated = async (page = 1, limit = 20) => {
648
+ return await controller.find('PublishedPost', {}, {
649
+ offset: (page - 1) * limit,
650
+ limit: limit,
651
+ orderBy: [{ field: 'publishedAt', direction: 'desc' }]
652
+ });
653
+ };
654
+
655
+ // Limit the amount of data used in computations
656
+ const TopPost = FilteredEntity.create({
657
+ name: 'TopPost',
658
+ baseEntity: Post,
659
+ filter: { status: 'published' },
660
+ options: {
661
+ orderBy: [{ field: 'viewCount', direction: 'desc' }],
662
+ limit: 100 // Only consider top 100 posts with highest view count
663
+ }
664
+ });
665
+ ```
666
+
667
+ ## Best Practices
668
+
669
+ ### 1. Design Filter Conditions Properly
670
+
671
+ ```javascript
672
+ // ✅ Efficient filter conditions
673
+ const EfficientFilter = FilteredEntity.create({
674
+ name: 'EfficientFilter',
675
+ baseEntity: Post,
676
+ filter: {
677
+ status: 'published', // Simple equality condition
678
+ category: { $in: ['tech', 'science'] } // Use index-friendly operations
679
+ }
680
+ });
681
+
682
+ // ❌ Inefficient filter conditions
683
+ const InefficientFilter = FilteredEntity.create({
684
+ name: 'InefficientFilter',
685
+ baseEntity: Post,
686
+ filter: {
687
+ $where: function() {
688
+ // Avoid using $where, it cannot use indexes
689
+ return this.title.toLowerCase().includes('javascript');
690
+ }
691
+ }
692
+ });
693
+ ```
694
+
695
+ ### 2. Avoid Over-filtering
696
+
697
+ ```javascript
698
+ // ✅ Reasonable filtering granularity
699
+ const PublishedPost = FilteredEntity.create({
700
+ name: 'PublishedPost',
701
+ baseEntity: Post,
702
+ filter: { status: 'published' }
703
+ });
704
+
705
+ const TechPost = FilteredEntity.create({
706
+ name: 'TechPost',
707
+ baseEntity: PublishedPost, // Based on existing filtered entity
708
+ filter: { category: 'technology' }
709
+ });
710
+
711
+ // ❌ Over-segmented filtered entities
712
+ const TechPostOnMonday = FilteredEntity.create({
713
+ name: 'TechPostOnMonday',
714
+ baseEntity: Post,
715
+ filter: {
716
+ category: 'technology',
717
+ status: 'published',
718
+ $expr: {
719
+ $eq: [{ $dayOfWeek: '$publishedAt' }, 2] // Too specific condition
720
+ }
721
+ }
722
+ });
723
+ ```
724
+
725
+ ### 3. Use Computations Appropriately
726
+
727
+ ```javascript
728
+ // ✅ Appropriate computations on filtered entities
729
+ const UserStats = Entity.create({
730
+ name: 'User',
731
+ properties: [
732
+ Property.create({
733
+ name: 'publishedPostCount',
734
+ type: 'number',
735
+ computation: new Count(PublishedPost, 'author') // Simple counting
736
+ })
737
+ ]
738
+ });
739
+
740
+ // ❌ Complex computations on filtered entities
741
+ const ComplexUserStats = Entity.create({
742
+ name: 'User',
743
+ properties: [
744
+ Property.create({
745
+ name: 'complexScore',
746
+ type: 'number',
747
+ computation: new Transform(
748
+ PublishedPost,
749
+ 'author',
750
+ (posts) => {
751
+ // Avoid complex data processing in computations
752
+ return posts.reduce((score, post) => {
753
+ return score + (post.viewCount * 0.1 + post.likeCount * 0.5);
754
+ }, 0);
755
+ }
756
+ )
757
+ })
758
+ ]
759
+ });
760
+ ```
761
+
762
+ ### 4. Monitor Performance
763
+
764
+ ```javascript
765
+ // Monitor filtered entity performance
766
+ const monitorFilteredEntity = (entityName) => {
767
+ controller.on(`${entityName}:query`, (event) => {
768
+ console.log(`Query ${entityName}:`, {
769
+ duration: event.duration,
770
+ resultCount: event.resultCount,
771
+ filter: event.filter
772
+ });
773
+
774
+ if (event.duration > 1000) { // Query takes more than 1 second
775
+ console.warn(`${entityName} query performance warning:`, event);
776
+ }
777
+ });
778
+ };
779
+
780
+ monitorFilteredEntity('PublishedPost');
781
+ monitorFilteredEntity('ActiveUser');
782
+ ```
783
+
784
+ Filtered entities provide powerful data viewing and computation capabilities for interaqt. By using filtered entities appropriately, you can create efficient, real-time updating data statistics and analysis systems while maintaining code clarity and maintainability.