Children
Children define nested collections within a projection. Each child represents a collection of items that are managed independently but belong to a parent projection.
Basic Syntax
Section titled “Basic Syntax”children {CollectionName} identified by {Identifier} {child blocks}Simple Example
Section titled “Simple Example”projection Group => GroupReadModel from GroupCreated Name = name
children members identified by userId from UserAddedToGroup key userId parent groupId Name = userName Role = roleThis creates a members collection where each member is identified by userId.
Identifier Expression
Section titled “Identifier Expression”The identified by specifies how to identify individual children:
children orders identified by orderIdchildren members identified by userIdchildren items identified by itemNumberParent Key
Section titled “Parent Key”Use parent to specify the relationship to the parent projection:
children members identified by userId from UserAddedToGroup key userId parent groupId Name = userNameThe parent groupId links the child to the correct parent instance.
With AutoMap
Section titled “With AutoMap”Apply AutoMap to children:
children members identified by userId automap
from UserAddedToGroup Role = roleMultiple Events
Section titled “Multiple Events”Children can have multiple event types:
children members identified by userId from UserAddedToGroup key userId parent groupId Name = userName Role = role
from UserRoleChanged key userId parent groupId Role = roleEvery Block in Children
Section titled “Every Block in Children”Apply mappings to all events within a children collection using the every block:
children members identified by userId from UserAddedToGroup key userId parent groupId Role = role
every Name = userName UpdatedAt = $eventContext.occurredThe every block within children works similarly to the top-level every block but applies only to events within that specific children collection. It’s useful for mappings that should apply to all events affecting child items.
Note: The exclude children directive is not applicable within child every blocks as they already operate in a children context.
Joins in Children
Section titled “Joins in Children”Children can have joins:
children members id userId from UserAddedToGroup key userId parent groupId UserId = userId Role = role
join User on UserId events UserCreated, UserUpdated Name = name Email = emailRemoval in Children
Section titled “Removal in Children”Remove children when specific events occur:
children members id userId from UserAddedToGroup key userId parent groupId Role = role
remove with UserRemovedFromGroup key userId parent groupIdSee Removal for more details.
Nested Children
Section titled “Nested Children”Children can contain their own children:
children departments id deptId from DepartmentCreated key deptId parent companyId Name = name
children teams id teamId from TeamCreated key teamId parent deptId Name = nameExamples
Section titled “Examples”Group Membership
Section titled “Group Membership”projection Group => GroupReadModel from GroupCreated Name = name Description = description
children members id userId automap
from UserAddedToGroup key userId parent groupId AddedAt = $eventContext.occurred
from UserRoleChanged key userId parent groupId Role = role
remove with UserRemovedFromGroup key userId parent groupIdOrder with Line Items
Section titled “Order with Line Items”projection Order => OrderReadModel from OrderPlaced OrderNumber = orderNumber CustomerId = customerId Total = 0
children items id lineNumber from LineItemAdded key lineNumber parent orderId ProductId = productId Quantity = quantity UnitPrice = price LineTotal = total
from LineItemQuantityChanged key lineNumber parent orderId Quantity = quantity LineTotal = total
remove with LineItemRemoved key lineNumber parent orderIdProject with Tasks
Section titled “Project with Tasks”projection Project => ProjectReadModel from ProjectCreated Name = name Status = "Active"
children tasks id taskId every LastModified = $eventContext.occurred
from TaskAdded key taskId parent projectId Title = title AssignedTo = assigneeId Status = "Open" CreatedAt = $eventContext.occurred
from TaskCompleted key taskId parent projectId Status = "Completed" CompletedAt = $eventContext.occurred
from TaskAssigned key taskId parent projectId AssignedTo = assigneeId
join User on AssignedTo events UserCreated AssigneeName = nameInvoice with Payments
Section titled “Invoice with Payments”projection Invoice => InvoiceReadModel from InvoiceIssued InvoiceNumber = number CustomerId = customerId Amount = amount Balance = amount
children payments id paymentId from PaymentReceived key paymentId parent invoiceNumber Amount = amount ReceivedAt = $eventContext.occurred Method = paymentMethod
from PaymentReceived subtract Balance by amountBlog Post with Comments
Section titled “Blog Post with Comments”projection BlogPost => BlogPostReadModel from PostPublished Title = title Content = content AuthorId = authorId PublishedAt = $eventContext.occurred
from PostUpdated Content = content UpdatedAt = $eventContext.occurred
children comments id commentId from CommentAdded key commentId parent postId AuthorId = authorId Content = content CreatedAt = $eventContext.occurred
from CommentEdited key commentId parent postId Content = content EditedAt = $eventContext.occurred
remove with CommentDeleted key commentId parent postId
join User on AuthorId events UserRegistered AuthorName = nameMulti-Level Nesting
Section titled “Multi-Level Nesting”projection Company => CompanyReadModel from CompanyCreated Name = name
children departments id deptId from DepartmentCreated key deptId parent companyId Name = name
children teams id teamId from TeamCreated key teamId parent deptId Name = name
children members id memberId from MemberAdded key memberId parent teamId Name = name Role = roleParent Key Expressions
Section titled “Parent Key Expressions”The parent key can use various expressions:
children items id itemId from ItemAdded key itemId parent orderId # Event property # or parent $eventContext.eventSourceId # Event source ID # or parent order.id # Nested propertyAutoMap with Children
Section titled “AutoMap with Children”AutoMap at the children level applies to all child events:
children members id userId automap
from UserAdded key userId parent groupId # Name, Email, etc. are auto-mapped
from UserUpdated key userId parent groupId # Updates are auto-mappedCollection Property
Section titled “Collection Property”The children block maps to a collection property on the read model:
public class GroupReadModel{ public string Name { get; set; } public List<GroupMember> Members { get; set; } = new();}
public class GroupMember{ public string UserId { get; set; } public string Name { get; set; } public string Role { get; set; }}Best Practices
Section titled “Best Practices”- Clear Identifiers: Use meaningful identifiers that clearly identify children
- Parent Keys: Always specify parent keys to maintain relationships
- Removal: Include removal logic for children that can be deleted
- Joins for Enrichment: Use joins to add related data to children
- Nested Carefully: Deep nesting can impact performance and complexity
- AutoMap Selectively: Use AutoMap for children when property names align
- Consistent Patterns: Use consistent event patterns across children
Common Patterns
Section titled “Common Patterns”Add/Update/Remove
Section titled “Add/Update/Remove”children items id itemId from ItemAdded key itemId parent parentId # properties
from ItemUpdated key itemId parent parentId # updated properties
remove with ItemRemoved key itemId parent parentIdEnrichment with Joins
Section titled “Enrichment with Joins”children members id userId from MemberAdded key userId parent groupId UserId = userId
join User on UserId events UserCreated, UserUpdated Name = name Email = email```pdl
### Versioning
```pdlchildren versions id versionNumber from VersionCreated key versionNumber parent documentId Content = content CreatedAt = $eventContext.occurred CreatedBy = authorId