Skip to main content
All CollectionsInteroperability
Introduction to Writing Filters for the TeselaGen API
Introduction to Writing Filters for the TeselaGen API

The "filter" field is a powerful feature that lets you construct complex queries to retrieve exactly the data you need from our application.

Andrés Ramirez avatar
Written by Andrés Ramirez
Updated over 2 months ago

Our API allows you to perform advanced searches using the filter parameter as in GraphQL queries.

This tutorial will guide you through the process of writing these filters for your own purposes, using the sequence entity as an example.


Understanding the Filter Object Structure

The filter parameter accepts a JSON object that defines your search criteria. There are two main types of filters you can use:

  • Simple Filters: Quick and straightforward filters for common queries.

  • Expressive Filters: Advanced filters that allow for complex logical conditions.


Simple Filters

Simple filters are the quickest way to filter data based on direct field-value pairs. They are ideal for straightforward queries where you know exactly what you're looking for.

Structure:

{ "<field_name>": <value_or_array_of_values> }

Examples of Simple Filters

Filtering by Single Value

Goal: Retrieve sequences with a specific name.

{ "name": "My great sequence" }

Filtering by Multiple Values

Goal: Retrieve sequences with specific IDs.

{ 
"id": [
"c15a8f8d-ab8c-4c53-ac97-c512d5237aed",
"a36382a4-bd70-4b9a-a9ee-5477c9c00151",
"b3239647-aa05-4771-bff8-f80261c29133"
]
}

Filtering by Multiple Fields

Goal: Retrieve sequences that are circular and of type OLIGO

{ "circular": false,  "sequenceTypeCode": "OLIGO"}


Expressive Filters

Expressive filters provide a more advanced way to construct complex queries using logical conditions and operators. They are useful when you need to write complex conditions, combine multiple conditions or apply nested logical operators.

Structure of Expressive Filters

An expressive filter is a JSON object that includes a root node with the following keys:

  • __objectType: Specifies the type of the object, typically "query".

  • type: Specifies the type of the node, the first node usually "root".

  • entity: The name of the entity you are querying, e.g., "sequence".

  • filters: An array of filter conditions or groups that define your query criteria.

Overall Structure:

{ 
"__objectType": "query",
"type": "root",
"entity": "<entity_name>",
"filters": [<filter_conditions_or_groups>]
}

Example of Root Node in an Expressive Filter:

The following filter root node can be used for getting records from the sequence entity:

{ 
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
...
]
}

Creating Basic Expressive Filters

In expressive filters, each condition is defined within the filters array of the root node.

Expression Filters

An expression filter allows you to compare a field to a value using an operator.

Structure:

{ 
"type": "expression",
"operator": "<operator>",
"field": "<field_name>",
"args": [<value>]
}

Operators:

  • "equals"

  • "notEquals"

  • "greaterThan"

  • "lessThan"

  • "greaterThanOrEqual"

  • "lessThanOrEqual"

  • "contains" (for strings and arrays)

Example: The following filter gets all sequences of sizes greater than 100:

{ 
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{ "type": "expression",
"operator": "greaterThan",
"field": "size",
"args": [100]
}
]
}

Example: Filter sequences which name field contains "construct" word

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "expression",
"operator": "contains",
"field": "name",
"args": [
"construct"
]
}
]
}

Example: Filter sequences which contains a feature with the name "operator O2"

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "expression",
"operator": "contains",
"field": "sequenceFeatures.name",
"args": [
"operator O2"
]
}
]
}

Where Filters

A where filter directly specifies field-value pairs for equality comparison.

Structure:

{ "type": "where", "args": { "<field_name>": <value> } }

Example: Get circular sequences which materials are tagged as externally available

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "where",
"args": {
"circular": true,
"polynucleotideMaterial.externalAvailability": true
}
}
]
}

Combining Filters with Logical Groups

To create more complex queries, you can combine multiple filters using logical operators ("and" and "or") within group filters. These group filters are included within the filters array of the root node.

Structure:

{ 
"__objectType": "query",
"type": "root",
"entity": "<entity_name>",
"filters": [
{
"type": "group",
"operator": "<logical_operator>",
"filters": [<filter_conditions_or_groups>]
}
]
}

Example: Combining Filters with AND

Goal: Find sequences that are larger than 500 bp and circular.

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "group",
"operator": "and",
"filters": [
{
"type": "expression",
"operator": "greaterThan",
"field": "size",
"args": [
500
]
},
{
"type": "expression",
"operator": "equals",
"field": "circular",
"args": [
true
]
}
]
}
]
}

Example: Combining Filters with OR

Goal: Find sequences that are either LINEAR_DNA or have "PCR" in their name.

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "group",
"operator": "or",
"filters": [
{
"type": "expression",
"operator": "equals",
"field": "sequenceTypeCode",
"args": [
"LINEAR_DNA"
]
},
{
"type": "expression",
"operator": "contains",
"field": "name",
"args": [
"PCR"
]
}
]
}
]
}

Building Nested Filter Groups

You can nest groups within groups to handle complex logical conditions. Each nested group is included within the filters array of its parent group.

Example: Complex Nested Filter

Goal: Find sequences that:

  • Are circular.

  • Are larger than 0 bp.

  • And (either internally available or externally available).

Filter:

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "group",
"operator": "and",
"filters": [
{
"type": "where",
"args": {
"circular": true
}
},
{
"type": "expression",
"operator": "greaterThan",
"field": "size",
"args": [
0
]
},
{
"type": "group",
"operator": "or",
"filters": [
{
"type": "expression",
"operator": "equals",
"field": "polynucleotideMaterial.internalAvailability",
"args": [
true
]
},
{
"type": "expression",
"operator": "equals",
"field": "polynucleotideMaterial.externalAvailability",
"args": [
true
]
}
]
}
]
}
]
}

Accessing Nested Fields

As you may have noted from previous examples, you can access nested fields (fields within related objects). When filtering on nested fields, use dot notation in the field key of your expression filters.

Example: Retrieve sequences related with a sample named "My sample"

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "expression",
"operator": "contains",
"field": "polynucleotideMaterial.samples.name",
"args": [
"My sample"
]
}
]
}

Tips for Writing Effective Filters

  • Choose the Right Filter Type: Use simple filters for straightforward queries and expressive filters for complex conditions.

  • Include the Root Node: In expressive filters, always include the root node with __objectType, type, and entity keys.

  • Validate Field Names: Ensure you're using the correct field names as defined in the entity schema.

  • Select Appropriate Operators: Choose the operator that best fits your comparison needs.

  • Test Incrementally: Start with simple filters and gradually add complexity to ensure each part works as expected.

  • Proper JSON Formatting: Make sure your JSON structure is properly formatted to avoid syntax errors.


Common Use Cases

Using Simple Filters

Filtering by tags

Goal: Retrieve sequences tagged as "Important"

{ 
"taggedItems.tag.name": [
"Important"
]
}

Filtering by Exact Match

Goal: Find sequences named "Example Sequence".

{ "name": "Example Sequence" }

Using Expressive Filters

Filtering by Date Range

Goal: Find sequences created within the last month.

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "group",
"operator": "and",
"filters": [
{
"type": "expression",
"operator": "greaterThanOrEqual",
"field": "createdAt",
"args": [
"2024-08-01T00:00:00Z"
]
},
{
"type": "expression",
"operator": "lessThanOrEqual",
"field": "createdAt",
"args": [
"2024-08-30T23:59:59Z"
]
}
]
}
]
}

Using NOT Conditions

Goal: Find sequences that are not LINEAR_DNA.

{
"__objectType": "query",
"type": "root",
"entity": "sequence",
"filters": [
{
"type": "expression",
"operator": "notEquals",
"field": "sequenceTypeCode",
"args": [
"LINEAR_DNA"
]
}
]
}

Conclusion

By leveraging both simple and expressive filters, you can perform highly customized queries against the TeselaGen API. Simple filters are great for straightforward queries, while expressive filters provide the flexibility needed for complex conditions. Remember to include the root node with __objectType, type, and entity in your expressive filters to ensure they are structured correctly. This powerful feature enables you to retrieve data that precisely matches your criteria, enhancing the efficiency and effectiveness of your data retrieval processes.

If you have any questions or need further assistance, please don't hesitate to reach out to our support team.


Did this answer your question?