Skip to main content

Query Sequences

As the number of recording sessions in your platform grows, browsing them manually becomes impractical. Mosaico's query system solves this with server-side filtering: instead of loading sessions and inspecting them locally, you describe what you are looking for and the daemon finds it for you. The client only receives the sessions that actually match. This keeps network traffic low and makes it feasible to search across thousands of recordings.

Sequence-level queries are the right tool when the criteria you care about live at the session level: the name of the mission, environment conditions logged at recording time, project identifiers, or any other metadata you attached to the Sequence when you created it. You are not yet asking questions about what sensor data is inside; you are asking questions about the recording session itself.

Querying Sequences by Name and Metadata

The QuerySequence builder constructs a filter by method chaining. Every .with_*() call you add becomes an additional AND condition: the daemon only returns sessions that satisfy every constraint you have specified. This makes it natural to start broad and progressively narrow; you can add conditions one at a time and the semantics are always "all of the above must be true."

with_name_match() performs a fuzzy substring match against the Sequence name. Passing "test_drive" will match any session whose name contains that string, so you do not need to know the exact recording name in advance. This is useful when you have a naming convention and want all recordings from a particular campaign.

with_user_metadata() works differently: it performs an exact or comparison-based match against a specific metadata field. The first argument is the field key, and the keyword arguments (eq, lt, gt, and so on) specify the predicate. When you stored metadata as a nested dictionary during ingestion, you can reach any level of nesting using dot notation. For example, "project.name" queries the name field inside the project sub-object, and "environment.visibility" queries a field two levels deep. Any structure you stored at recording time is queryable this way.

The example below finds every Sequence whose name contains "test_drive", whose project name is exactly "Apollo", and whose recorded visibility was below 50.

Query by name and metadata
from mosaicolabs import MosaicoClient, QuerySequence

with MosaicoClient.connect("localhost", 6726) as client:
results = client.query(
QuerySequence()
.with_name_match("test_drive")
.with_user_metadata("project.name", eq="Apollo")
.with_user_metadata("environment.visibility", lt=50)
)

if results:
for item in results:
print(f"Matched Sequence: {item.sequence.name}")
print(f" Topics: {[topic.name for topic in item.topics]}")

client.query() returns None on error, or a QueryResponse, a list of QueryResponseItem objects, one per matched Sequence. Each item carries two things: item.sequence, which holds the metadata of the matched session (its name, time boundary, and any stored metadata), and item.topics, which is the list of Topics that belong to that session. Because this is a Sequence-level query with no Topic filter applied, item.topics contains every Topic recorded under that Sequence, giving you a complete picture of what sensor streams are available before you decide which ones to open.

Result Normalization

topic.name returns the relative path (e.g. /front/camera/image), directly usable with other SDK methods like topic_handler() and streamers.

Key Concepts

Convenience methods like with_name_match() and with_user_metadata() cover the most common filtering patterns. with_name_match() is intentionally fuzzy so you can match recording names without knowing them exactly. with_user_metadata() gives you precise control over any field you stored at ingestion time, with a full set of comparison operators.

Generic methods using with_expression() and the .Q proxy give you access to the full operator set (.gt(), .lt(), .between(), and others) when the convenience methods do not cover your use case. The .Q proxy builds type-safe field paths from Ontology models, ensuring that the field names in your query match the actual schema.

Dynamic metadata through dot notation means you can query any depth of nesting in the metadata you stored at recording time. There is no fixed schema for user metadata; whatever JSON-like structure you attached to the Sequence is fully searchable using "key.subkey.deeper" paths.