Sorting in queries
Updated: Oct 6, 2025
Queries and
filters are used to find entities which meet certain criteria. The entities returned by a query are not necessarily in a useful order. For example, if you want to find the entity with an
IntAttribute that has the biggest value, you need to sort the entities returned by a query.
A Query object has a sort API. You can specify the sorting criteria by calling the with function. You can also specify the number of returned elements using the take API. All of these functions are executed on the C++ side, and are much faster than using a Kotlin filter, if you have a large number of entities.
Inside of the
with function, you can specify the sorting criteria by calling the
by function. The
by function takes a
AttributeData object as a parameter.
// Sorts entities by the value of the attribute intAttr
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.intAttrData)
}
}
.eval()
The take API takes two integers as a parameter. The first integer represents offset, specifying the number of elements to skip. The second integer is count, specifying the number of elements to return from starting at offset.
// Sorts entities by the value of the attribute intAttr, and returns the first 10 elements
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.intAttrData)
}
take(0, 10)
}
.eval()
Sort entities based on intAttr
The code below shows how to use IntAttribute to sort entities based on the data of the attribute intAttr.
// Sorts entities by the value of the attribute intAttr, in ascending order
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.intAttrData).asc()
}
}
.eval()
// Sorts entities by the value of the attribute intAttr, in descending order
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.intAttrData).desc()
}
}
.eval()
By default, the sorting order is ascending. You can use the asc() and desc() functions to specify the sorting order. FloatAttribute, LongAttribute, and TimeAttribute have identical APIs to those of IntAttribute.
Filter based on stringAttr
The code below shows how to use StringAttribute to filter entities based on the data of the attribute stringAttr.
// Sorts entities by the value of the attribute stringAttr, in ascending order
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.stringAttrData).asc()
}
}
.eval()
// Sorts entities by the value of the attribute stringAttr, in descending order, case-insensitively, and returns the first 10 elements
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.stringAttrData).descCaseInsensitive()
}
take(0, 10)
}
.eval()
Filter based on vector data
The code below shows how to use Vector4Attribute to filter entities based on the data of the attribute vector4Attr.
// Sorts entities by the value of the attribute vector4Attr's x property, in ascending order
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.vector4AttrData).byX().asc()
}
}
.eval()
// Sorts entities by the value of the attribute vector4Attr's w property, in descending order
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.vector4AttrData).byW().desc()
}
}
.eval()
If byX(), byY(), byZ(), or byW() is not called, the sorting will be done based on the X property of the vector. Vector2Attribute, Vector3Attribute, and Vector4Attribute have similar APIs to those of Vector4Attribute.
The code below shows how to use PoseAttribute to filter entities based on the data of the attribute poseAttr.
// Sorts entities by the value of the attribute poseAttr's position's x property, in ascending order
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.poseAttrData).byPositionX().asc()
}
}
.eval()
// Sorts entities by the value of the attribute poseAttr's orientation's w property, in descending order
val sortedEntities = Query.where { has(TestComponent.id) }
.sort {
with {
by(TestComponent.poseAttrData).byOrientationW().desc()
}
}
.eval()
Kotlin sorting versus native sorting
The two queries below will return the same results, but the first uses a Kotlin sorting function and the second uses a native sorting function.
val droneEntities0 =
Query.where { has(DroneComponent.id, Transform.id) }
.eval()
.sortedBy { it.getComponent<DroneComponent>().rotationSpeed }
val droneEntities1 =
Query.where { has(DroneComponent.id, Transform.id) }
.sort { with { by(DroneComponent.rotationSpeedData) } }
.eval()
For a query with thousands of entities, using a native sorting function can be 100 times more efficient than using a Kotlin sorting function. This is because it.getComponent<DroneComponent>() is a function that creates a new DroneComponent object for each entity, and object creation in large numbers is slow in Kotlin. Meanwhile, .sort { with { by(DroneComponent.rotationSpeedData) } } is an API that directly accesses the data of the DroneComponent on the C++ side, and is much faster than creating a new DroneComponent object.