Develop
Develop
Select your platform

Query for child components

Updated: Jun 20, 2025

Overview

The childrenOf is an advanced and experimental query which allows you to retrieve a list of entities that are considered children of a specified parent entity based on a linked entity attribute. This is particularly useful for creating parent-child relationships between entities.

How it works

The childrenOf query takes two parameters:
  1. The parent entity
  2. The ID of the linked entity attribute that defines the parent-child relationship
When the query runs, it returns all entities that have the specified attribute pointing to the parent entity.

Setting up linked entity attribute

Before you can use childrenOf queries, you need to register the entity attribute as a linked entity attribute:
// Do this in your Activity's onCreate method:
EntityContext.getDataModel()!!.registerLinkedEntityAttribute(MyComponent.parentId)
// MyComponent should have an entity attribute called "parent", and "MyComponent.parentId" is the ID of that attribute
This tells the DataModel to build and maintain a hierarchy based on this attribute, which enables efficient querying of parent-child relationships.

Example usage

Here’s an example of using childrenOf queries in a “tree” hierarchy system:
@OptIn(SpatialSDKExperimentalAPI::class)
class TreeHierarchySystem : SystemBase() {

    init() {
        // Register the parent entity attribute as a linked entity attribute
        EntityContext.getDataModel()!!.registerLinkedEntityAttribute(TreeNode.parentId)
    }

    override fun execute() {
        // Process all root nodes (nodes without parents), assuming top-level entities also have a TreeNode component
        val rootNodesQuery = Query.where { has(TreeNode.id) }
                                  .filter { by(TreeNode.parentData).isEqualTo(Entity.nullEntity()) }
        for (rootEntity in rootNodesQuery.eval()) {
            processNodeAndChildren(rootEntity)
        }
    }

    private fun processNodeAndChildren(entity: Entity) {
        // Process this node
        val treeNode = entity.getComponent<TreeNode>()

        // Apply any node-specific logic here
        // ...
        println("Processing node: ${treeNode.name}")

        // Find and process all children of this node
        val childrenQuery = Query.where { childrenOf(entity, TreeNode.parentId) }
        for (childEntity in childrenQuery.eval()) {
            processNodeAndChildren(childEntity)
        }
    }
}
Below is TreeNode’s XML definition:
<?xml version="1.0" encoding="utf-8"?>
<ComponentSchema packageName="test.package.name">
  <Component name="TreeNode" >
    <EntityAttribute name="parent" />
    <StringAttribute name="name" />
  </Component>
</ComponentSchema>
In this example:
  1. The TreeHierarchySystem manages a hierarchy of tree nodes.
  2. In the init method, TreeNode.parentId is registered as a linked entity attribute. Note that this is a required step for using childrenOf queries and typically happens in the Activity’s onCreate lifecycle callback.
  3. In the execute method, the system first finds all root nodes (nodes without parents).
  4. For each root node, the system processes it and then recursively processes all its children.
  5. The system uses childrenOf(entity, TreeNode.parentId) to query for all direct children of a node.
Consider the following example tree structure:
/**
 *
 *          A
 *         / \
 *        B   C
 *       / \   \
 *      D   E   F
 */
val A = Entity.create()
val B = Entity.create()
val C = Entity.create()
val D = Entity.create()
val E = Entity.create()
val F = Entity.create()
A.setComponent(TreeNode(parent = Entity.nullEntity(), name = "A"))
B.setComponent(TreeNode(parent = A, name = "B"))
C.setComponent(TreeNode(parent = A, name = "C"))
D.setComponent(TreeNode(parent = B, name = "D"))
E.setComponent(TreeNode(parent = B, name = "E"))
F.setComponent(TreeNode(parent = C, name = "F"))
When the TreeHierarchySystem executes, it will first find the root nodes (A) and then process them. It will then recursively process all their children (B, C), and so on, resulting in the following output:
Processing node: A
Processing node: B
Processing node: D
Processing node: E
Processing node: C
Processing node: F

Best practices

  • Register linked entity attributes in your Activity’s onCreate method.
  • Use meaningful attribute names for parent-child relationships to make your code more readable.
  • Consider the performance implications of deep hierarchies, as traversing large trees can be expensive.
Did you find this page helpful?
Thumbs up icon
Thumbs down icon