Querying
Every model (see Models) exposes a .where() classmethod for fetching
records from the One Codex server. Each keyword argument is a field to filter on,
and its value is either a literal to match exactly or a Mongo-style operator
dict:
ocx.Samples.where(filename="SRR1234.fastq.gz")
ocx.Samples.where(filename={"$icontains": "patient"})
Filters combine with a logical AND, and filtering happens server-side, so a
single .where() call is much faster than fetching records and looping:
ocx.Samples.where(visibility="private", size={"$gte": 1_000_000})
Which operators a field accepts depends on the type of that field, not on the
model it belongs to — $icontains behaves the same on Samples.filename as
it does on Documents.filename. Each model’s .where() signature declares
the type of every field it accepts, so filename: str | StrFilter means
filename takes either a plain string or a StrFilter operator dict. The
sections below describe each of those operator shapes; they are defined in
onecodex.models.filters and may be imported if you want to annotate a
filter you are building up:
from onecodex.models.filters import NumFilter
big: NumFilter = {"$gte": 1_000_000}
ocx.Samples.where(size=big)
All operator keys are optional.
Strings
StrFilter — e.g. Samples.filename, Samples.status,
Projects.name, Documents.filename.
Operator |
Matches |
|---|---|
|
Exact (in)equality. |
|
Any value in the given sequence. |
|
Substring, case-sensitive and case-insensitive. |
|
Prefix, case-sensitive and case-insensitive. |
|
Suffix, case-sensitive and case-insensitive. |
ocx.Samples.where(filename={"$iendswith": ".fastq.gz"})
ocx.Samples.where(filename={"$icontains": "patient"})
ocx.Samples.where(error_msg=None)
Enum-backed strings
EnumStrFilter — Metadata.platform, Metadata.library_type and
Metadata.sample_type. Samples.status, Samples.visibility and
Assets.status behave the same way.
These fields accept a fixed set of values. Filter them with $eq, $ne or
$in, passing a complete value:
ocx.Metadata.where(platform="Illumina NovaSeq 6000")
ocx.Metadata.where(platform={"$in": ["Illumina HiSeq", "Illumina MiSeq"]})
ocx.Metadata.where(library_type="Targeted/16S")
ocx.Samples.where(status="available")
The shorter sets are:
Field |
Allowed values |
|---|---|
|
|
|
|
|
|
|
|
platform has many more – Illumina NovaSeq 6000, Oxford Nanopore
MinION, PacBio Revio and so on.
Note
The value must be one of the allowed values. A partial value such as
"Oxford" is rejected with an error rather than returning no results.
Numbers
NumFilter — e.g. Samples.size, Documents.size,
Metadata.location_lat.
Operator |
Matches |
|---|---|
|
Exact (in)equality. |
|
Ordered comparison. |
|
A |
|
Any value in the given sequence. |
ocx.Samples.where(size={"$gte": 1_000_000})
ocx.Samples.where(size={"$between": [1_000_000, 5_000_000]})
Datetimes
DatetimeFilter — e.g. Samples.created_at, Samples.updated_at,
Metadata.date_collected.
The same operators as NumFilter: $eq, $ne, $lt, $lte,
$gt, $gte, $between and $in.
Warning
Datetime values must be RFC3339 strings with a timezone offset, not
datetime.datetime objects — the latter are not JSON-serializable and will
raise when the query is encoded. Call .isoformat() at the call site.
from datetime import datetime, timedelta, timezone
since = (datetime.now(timezone.utc) - timedelta(days=30)).isoformat()
ocx.Samples.where(created_at={"$gte": since})
Booleans
BoolFilter — e.g. Classifications.complete, Classifications.success,
Metadata.starred.
Accepts $eq and $ne only. Passing a bare boolean is usually clearer:
ocx.Classifications.where(complete=True, success=True)
References to other models
RefFilter — e.g. Samples.project, Samples.owner,
Classifications.sample.
Reference fields accept $eq, $ne and $in. Values may be a model
instance or an id string, used interchangeably:
project = ocx.Projects.get("d53ad03b010542e3")
ocx.Samples.where(project=project)
ocx.Samples.where(project="d53ad03b010542e3")
ocx.Samples.where(project={"$in": [project, "another_project_id"]})
ocx.Samples.where(project=None) # samples not in any project
Lists of references
ListRefFilter — fields holding a list of references, such as
Samples.tags.
Accepts $containsall (every given reference must be present) and
$containsany (at least one must be present). For tags specifically,
Samples.where() takes a plain list and builds the $containsall query for
you, resolving each entry by tag name, id, or Tags
instance:
ocx.Samples.where(tags=["isolate"])
ocx.Samples.where(tags=["16S", "isolate"])
An unrecognized tag name raises rather than returning an empty result.
Fetching by ID
Positional arguments to .where() are treated as record IDs, which is a
convenient way to fetch several known records in a single request:
ocx.Samples.where("761bc54b97f64980", "0a1b2c3d4e5f6789")
Passing a single dict positionally sends it as a raw query, for cases the
keyword arguments do not cover:
ocx.Samples.where({"visibility": "private", "filename": "tmp.fa"})
To fetch one record, use .get(), which returns None when the record does
not exist or is not visible to you. To fetch every record, use .all().
Filtering client-side
Not every question can be answered by the server. The filter keyword takes a
callable applied to each fetched record, keeping those for which it returns a
truthy value:
ocx.Samples.where(public=True, limit=100, filter=lambda s: not s.tags)
Because this runs after fetching, it narrows results but does not reduce the
amount of data transferred — prefer a server-side filter where one exists.
SampleCollection results also offer a
.filter() method for
the same purpose.
Note
Metadata.custom is a free-form dictionary and is not server-filterable.
Fetch a broader set of samples and filter on it client-side.