Skip to main content

Query Builder

RevitPy provides a LINQ-style QueryBuilder for querying Revit elements. It supports filtering, sorting, pagination, and several terminal operations to retrieve results.

The QueryBuilder is defined in revitpy.api.query and is accessible from the RevitAPI class.

Creating Queries

There are several ways to create a query.

From RevitAPI

from revitpy import RevitAPI

api = RevitAPI()
api.connect(revit_application)

# Query all elements
query = api.elements

# Query a specific element type
query = api.query(WallElement)

From the Query Factory

The Query class provides static factory methods:

from revitpy.api.query import Query

# From an element provider
query = Query.from_provider(provider)

# From a list of elements
query = Query.from_elements(element_list)

# Typed query
query = Query.of_type(provider, WallElement)

Filter Methods

All filter methods return a new QueryBuilder, so they can be chained.

where

The general-purpose filter method. Accepts a property name, a FilterOperator, and an optional value:

from revitpy.api.query import FilterOperator

query.where("Name", FilterOperator.EQUALS, "Wall-1")
query.where("Height", FilterOperator.GREATER_THAN, 3.0)
query.where("Comments", FilterOperator.CONTAINS, "structural", case_sensitive=False)

Signature:

def where(
    self,
    property_name: str,
    operator: FilterOperator,
    value: Any = None,
    case_sensitive: bool = True,
) -> QueryBuilder[T]

Convenience Filter Methods

These methods wrap where for common operations:

Method Equivalent FilterOperator Example
equals(prop, value) EQUALS query.equals("Name", "Wall-1")
not_equals(prop, value) NOT_EQUALS query.not_equals("Type", "Default")
contains(prop, value) CONTAINS query.contains("Name", "Wall")
starts_with(prop, value) STARTS_WITH query.starts_with("Name", "W")
ends_with(prop, value) ENDS_WITH query.ends_with("Name", "-1")
in_values(prop, values) IN query.in_values("Type", ["A", "B"])
is_null(prop) IS_NULL query.is_null("Comments")
is_not_null(prop) IS_NOT_NULL query.is_not_null("Mark")
regex(prop, pattern) REGEX query.regex("Name", r"Wall-\d+")

All string-based filters (equals, not_equals, contains, starts_with, ends_with, regex) accept an optional case_sensitive parameter that defaults to True.

FilterOperator Enum

The FilterOperator enum defines all supported comparison operators:

Value Description
EQUALS Exact equality
NOT_EQUALS Inequality
GREATER_THAN Greater than
LESS_THAN Less than
GREATER_EQUAL Greater than or equal
LESS_EQUAL Less than or equal
CONTAINS String contains substring
STARTS_WITH String starts with prefix
ENDS_WITH String ends with suffix
IN Value is in a list
NOT_IN Value is not in a list
IS_NULL Value is None
IS_NOT_NULL Value is not None
REGEX Matches a regular expression

Sorting

order_by

Sort by a property name with a specified direction:

from revitpy.api.query import SortDirection

query.order_by("Name", SortDirection.ASCENDING)
query.order_by("Height", SortDirection.DESCENDING)

order_by_ascending / order_by_descending

Convenience methods that set the direction explicitly:

query.order_by_ascending("Name")
query.order_by_descending("Height")

Multiple sort criteria can be chained. They are applied in the order they are added.

SortDirection Enum

Value Description
ASCENDING Sort in ascending order (A-Z, 0-9)
DESCENDING Sort in descending order (Z-A, 9-0)

Pagination

skip

Skip a number of elements from the beginning of the result set:

query.skip(10)

take

Limit the number of elements returned:

query.take(25)

Combining skip and take

# Get elements 11-35 (page 2, 25 per page)
results = query.order_by_ascending("Name").skip(10).take(25).execute()

distinct

Get distinct elements, optionally by a property name:

# Distinct elements (by element identity)
query.distinct()

# Distinct by a specific property
query.distinct("Type")

Terminal Operations

Terminal operations execute the query and return results. Once called, the query is evaluated against the element provider.

execute

Executes the query and returns an ElementSet:

element_set = query.equals("Type", "Wall").execute()

count

Returns the number of matching elements:

total = query.equals("Type", "Wall").count()

first

Returns the first matching element. Raises ElementNotFoundError if no elements match:

element = query.equals("Name", "Wall-1").first()

first_or_default

Returns the first matching element, or a default value if none match:

element = query.equals("Name", "Wall-1").first_or_default(default=None)

single

Returns the single matching element. Raises an error if zero or more than one element matches:

element = query.equals("Name", "Wall-1").single()

to_list

Executes the query and returns results as a plain Python list:

elements = query.equals("Type", "Wall").to_list()

any

Returns True if at least one element matches the query:

has_walls = query.equals("Type", "Wall").any()

Chaining Example

Filters, sorts, and pagination can be chained together in a single expression:

results = (
    api.elements
    .contains("Name", "Wall", case_sensitive=False)
    .is_not_null("Comments")
    .order_by_ascending("Name")
    .skip(0)
    .take(50)
    .execute()
)

for element in results:
    print(f"{element.name}: {element.get_parameter_value('Comments')}")

ElementSet

The execute() method returns an ElementSet, which is a generic collection with additional operations:

  • count – Property returning the number of elements.
  • where(predicate) – Filter with a callable predicate.
  • select(selector) – Transform elements with a callable selector.
  • first(predicate=None) – Get the first element, optionally matching a predicate.
  • first_or_default(predicate=None, default=None) – Get the first element or a default.
  • single(predicate=None) – Get the single matching element.
  • to_list() – Convert to a plain list.
  • any(predicate=None) – Check if any elements match.
  • all(predicate) – Check if all elements match a predicate.
  • order_by(key_selector) – Sort by a key function.
  • group_by(key_selector) – Group into a dictionary keyed by the selector.

ElementSet supports iteration, len(), and indexing with [].