select()
Returns an ECMModelQuerySync (sync) or ECMModelQueryAsync (async) that can be used to search, filter, and sort objects.
ECM Model reference — for a full description of all system properties (system.id, system.rights, system.base_params, system.file_properties, etc.) and how change tracking works.
1. Signature
-
Sync
-
Async
ecm.dms.select(model_class: type[T]) -> ECMModelQuerySync[T]
await ecm.dms.select(model_class: type[T]) -> ECMModelQueryAsync[T]
2. Parameters
| Name | Type | Description |
|---|---|---|
|
|
The model class describing the object type. Can also be created dynamically via |
3. Query builder methods
The returned query builder supports the following methods (chainable):
| Method | Description |
|---|---|
|
Add filter conditions. Multiple arguments are combined with AND. Conditions can be combined with |
|
Set the sort order. Argument position determines sort priority. Each argument is an |
|
Maximum total number of results across all pages. |
|
Number of objects per server request (default: 1000). Affects efficiency for large result sets. |
|
Zero-based start offset. Skips the first |
|
Include access rights data (populates |
|
Include audit metadata (populates |
|
Include file properties (populates |
|
Include document variant data. |
|
Include icon IDs for returned objects. |
|
Include remarks for returned objects. |
|
Return only the specified fields (sets |
|
Return only objects from the recycle bin. |
|
Switch to a HOL query that includes child objects. Returns an |
|
Switch to a HOL query that includes parent objects. Returns an |
|
Execute the query and return all results as a list (all pages in memory). |
|
Execute the query page by page and return a generator. Recommended for large result sets. |
|
|
4. Filter conditions (where)
Conditions are passed to .where(). Multiple arguments in a single .where() call are automatically combined with AND. For OR combinations, conditions are joined with the | operator; for AND with &.
4.1. Comparison operators
| Syntax | Operator | Example |
|---|---|---|
|
Equality |
|
|
Inequality |
|
|
Less than |
|
|
Less than or equal |
|
|
Greater than |
|
|
Greater than or equal |
|
|
Matches one of the values |
|
|
Matches none of the values |
|
|
Between two values (inclusive) |
|
4.2. AND combinations
Multiple arguments in .where() are combined with AND. The & operator can also be used explicitly:
# Variant 1: multiple arguments → AND
ecm.dms.select(InvoiceFolder).where(
InvoiceFolder.Year >= 2020,
InvoiceFolder.Status == "Approved",
)
# Variant 2: explicit & → same result
ecm.dms.select(InvoiceFolder).where(
(InvoiceFolder.Year >= 2020) & (InvoiceFolder.Status == "Approved")
)
4.3. OR combinations
Conditions are combined into an OR group using |:
ecm.dms.select(InvoiceFolder).where(
(InvoiceFolder.Status == "Open") | (InvoiceFolder.Status == "In Progress")
)
For value sets, .in_() is more concise:
ecm.dms.select(InvoiceFolder).where(
InvoiceFolder.Status.in_("Open", "In Progress")
)
4.4. Mixed AND/OR groups
& and | can be nested arbitrarily. Python parentheses control the evaluation order:
-
Sync
-
Async
# (Year >= 2020 AND Year <= 2024) AND (Status = "Open" OR Status = "In Progress")
for folder in (
ecm.dms.select(InvoiceFolder)
.where(
(InvoiceFolder.Year >= 2020) & (InvoiceFolder.Year <= 2024),
InvoiceFolder.Status.in_("Open", "In Progress"),
)
.stream()
):
print(folder.Title, folder.Year)
async for folder in (
ecm.dms.select(InvoiceFolder)
.where(
(InvoiceFolder.Year >= 2020) & (InvoiceFolder.Year <= 2024),
InvoiceFolder.Status.in_("Open", "In Progress"),
)
.stream()
):
print(folder.Title, folder.Year)
4.5. between()
.between(lower, upper) is a compact alternative to >= + ⇐:
-
Sync
-
Async
for folder in (
ecm.dms.select(InvoiceFolder)
.where(InvoiceFolder.Year.between(2020, 2024))
.stream()
):
print(folder.Title)
async for folder in (
ecm.dms.select(InvoiceFolder)
.where(InvoiceFolder.Year.between(2020, 2024))
.stream()
):
print(folder.Title)
4.6. Combined queries across multiple object types
Conditions in .where() can reference fields from different object types within the same cabinet. The server returns only those objects where all conditions are satisfied — regardless of which object type a condition refers to.
The following combinations are supported:
-
Search for a document with conditions on fields of the document itself, its register, and its folder.
-
Search for a register or folder that contains a child object matching a given condition.
|
When registers are nested, only the immediately enclosing register is available; parent registers above it are not. |
Search for a document — with conditions on register and folder:
-
Sync
-
Async
from tests.models.Unittest_DMS import Unittest_DMS, Unittest_DMS_Register, Unittest_DMS_Document
for doc in (
ecm.dms.select(Unittest_DMS_Document)
.where(
Unittest_DMS_Document.StringField == "Invoice",
Unittest_DMS_Register.Name == "Incoming invoices",
Unittest_DMS.Name == "Supplier GmbH",
)
.stream()
):
print(doc.system.id, doc.Name)
async for doc in (
ecm.dms.select(Unittest_DMS_Document)
.where(
Unittest_DMS_Document.StringField == "Invoice",
Unittest_DMS_Register.Name == "Incoming invoices",
Unittest_DMS.Name == "Supplier GmbH",
)
.stream()
):
print(doc.system.id, doc.Name)
Search for a folder — that contains a document matching a condition:
-
Sync
-
Async
from tests.models.Unittest_DMS import Unittest_DMS, Unittest_DMS_Document
for folder in (
ecm.dms.select(Unittest_DMS)
.where(
Unittest_DMS.Name == "Supplier GmbH",
Unittest_DMS_Document.StringField == "Invoice",
)
.stream()
):
print(folder.system.id, folder.Name)
async for folder in (
ecm.dms.select(Unittest_DMS)
.where(
Unittest_DMS.Name == "Supplier GmbH",
Unittest_DMS_Document.StringField == "Invoice",
)
.stream()
):
print(folder.system.id, folder.Name)
5. Sorting
The sort order is set via .order_by(). Each argument is an ECMSortOrder produced by .ASC or .DESC on an ECMField at class level. Argument position determines sort priority.
-
Sync
-
Async
# Primary sort by year descending, secondary by title ascending
for folder in (
ecm.dms.select(InvoiceFolder)
.order_by(InvoiceFolder.Year.DESC, InvoiceFolder.Title.ASC)
.stream()
):
print(folder.Year, folder.Title)
async for folder in (
ecm.dms.select(InvoiceFolder)
.order_by(InvoiceFolder.Year.DESC, InvoiceFolder.Title.ASC)
.stream()
):
print(folder.Year, folder.Title)
6. Pagination
.limit(), .pagesize() and .offset() restrict the result set and control internal page navigation.
| Method | Default | Description |
|---|---|---|
|
unlimited |
Maximum total number of results across all pages. |
|
1000 |
Number of objects per server request. Smaller values reduce per-page memory usage but increase the number of requests. Large values can overload the server — see the warning below. |
|
0 |
Skip the first |
-
Sync
-
Async
# Page 3 with 20 entries each (offset = 2 × 20 = 40), sorted by year descending
for folder in (
ecm.dms.select(InvoiceFolder)
.order_by(InvoiceFolder.Year.DESC)
.limit(20)
.offset(40)
.stream()
):
print(folder.system.id, folder.Title)
async for folder in (
ecm.dms.select(InvoiceFolder)
.order_by(InvoiceFolder.Year.DESC)
.limit(20)
.offset(40)
.stream()
):
print(folder.system.id, folder.Title)
|
A pagesize that is too large can cause the server to crash. Memory consumption per page grows proportionally to the number of objects multiplied by the requested metadata. The combination of large pages with As a rule of thumb: keep the default of 1000 and only adjust when a proven performance problem exists — and then reduce rather than increase. |
7. Rights information
.rights() retrieves the access rights of the logged-in user for each object. The rights are available in obj.system.rights as an ECMModelRights instance.
| Attribute | Description |
|---|---|
|
May create child objects (registers/documents in a folder, documents in a register). |
|
May change the index fields of the object. |
|
May read the file of the document. |
|
May modify the file of the document. |
|
May delete the object. |
-
Sync
-
Async
for folder in ecm.dms.select(InvoiceFolder).rights().stream():
r = folder.system.rights
if r.edit_metadata:
print(f"{folder.system.id}: editing allowed")
if not r.delete:
print(f"{folder.system.id}: deletion not permitted")
async for folder in ecm.dms.select(InvoiceFolder).rights().stream():
r = folder.system.rights
if r.edit_metadata:
print(f"{folder.system.id}: editing allowed")
if not r.delete:
print(f"{folder.system.id}: deletion not permitted")
8. Base parameters
.base_params() retrieves administrative information stored by the server for each object. The data is available in obj.system.base_params as an ECMModelBaseParams instance.
| Attribute | Description |
|---|---|
|
Username of the creator. |
|
Date of creation. |
|
Current owner of the object. |
|
Username of the last modifier. |
|
Timestamp of the last modification. |
|
Number of links. |
|
Number of text notices. |
-
Sync
-
Async
for folder in ecm.dms.select(InvoiceFolder).base_params().stream():
bp = folder.system.base_params
print(f"Created by {bp.creator} on {bp.creation_date}")
print(f"Last modified by {bp.modifier} on {bp.modified_date}")
async for folder in ecm.dms.select(InvoiceFolder).base_params().stream():
bp = folder.system.base_params
print(f"Created by {bp.creator} on {bp.creation_date}")
print(f"Last modified by {bp.modifier} on {bp.modified_date}")
9. File properties
.file_properties() retrieves metadata about the file of a document. Only available for ECMDocumentModel types; obj.system.file_properties returns an ECMModelFileProperties instance.
| Attribute | Description |
|---|---|
|
Number of files (primary and secondary files). |
|
File size in bytes. |
|
File extension (e.g. |
|
MIME type (e.g. |
|
MIME group (e.g. |
|
ID of the file type icon. |
|
Number of pages (if known). |
-
Sync
-
Async
for doc in ecm.dms.select(InvoiceDocument).file_properties().stream():
fp = doc.system.file_properties
print(f"{doc.system.id}: {fp.extension}, {fp.size} bytes, {fp.documentpagecount} pages")
async for doc in ecm.dms.select(InvoiceDocument).file_properties().stream():
fp = doc.system.file_properties
print(f"{doc.system.id}: {fp.extension}, {fp.size} bytes, {fp.documentpagecount} pages")
10. Variants
.variants() retrieves the version branches of a document from the W-module. Only relevant for document types with the W-module enabled. The result is available in obj.system.variants as a list of ECMModelDocumentVariant instances.
Each variant has the attributes doc_id, doc_ver, is_active, doc_parent and children.
-
Sync
-
Async
for doc in ecm.dms.select(InvoiceDocument).variants().stream():
for variant in doc.system.variants:
active = "✓" if variant.is_active else " "
print(f"[{active}] {variant.doc_ver} (ID {variant.doc_id})")
async for doc in ecm.dms.select(InvoiceDocument).variants().stream():
for variant in doc.system.variants:
active = "✓" if variant.is_active else " "
print(f"[{active}] {variant.doc_ver} (ID {variant.doc_id})")
11. Remarks
.remarks() includes the text notices of an object in the response. The data is available in obj.system.remarks.
-
Sync
-
Async
for folder in ecm.dms.select(InvoiceFolder).remarks().stream():
for remark in folder.system.remarks:
print(remark)
async for folder in ecm.dms.select(InvoiceFolder).remarks().stream():
for remark in folder.system.remarks:
print(remark)
12. Restricting fields (fields)
.fields() loads only the specified index fields from the server. The server internally sets field_schema="MIN" and transfers only the explicitly listed fields. System fields (system.id, system.name, etc.) and sort fields are always included regardless of this list.
This significantly reduces the amount of data transferred when only a few fields are needed. Fields that were not requested are None on the returned object.
Fields can be passed as ECMField class attributes or as internal field name strings. Calling without arguments resets the restriction and returns all fields again.
-
Sync
-
Async
# Load only Title and Year — all other fields are None
for folder in (
ecm.dms.select(InvoiceFolder)
.fields(InvoiceFolder.Title, InvoiceFolder.Year)
.stream()
):
print(folder.Title, folder.Year)
# folder.Status is None (not loaded)
async for folder in (
ecm.dms.select(InvoiceFolder)
.fields(InvoiceFolder.Title, InvoiceFolder.Year)
.stream()
):
print(folder.Title, folder.Year)
Fields can alternatively be passed as strings when no typed model is available:
-
Sync
-
Async
from ecmind_blue_client.ecm.model import make_folder_model
InvoiceFolder = make_folder_model("InvoiceFolder")
for folder in (
ecm.dms.select(InvoiceFolder)
.fields("Title", "Year")
.stream()
):
print(folder["Title"], folder["Year"])
async for folder in (
ecm.dms.select(InvoiceFolder)
.fields("Title", "Year")
.stream()
):
print(folder["Title"], folder["Year"])
13. Recycle bin
.garbage_mode() restricts the query to deleted objects. Without this call only non-deleted objects are returned.
-
Sync
-
Async
# List all deleted invoice folders
for folder in ecm.dms.select(InvoiceFolder).garbage_mode().stream():
print(f"Deleted: {folder.system.id} – {folder.Title}")
async for folder in ecm.dms.select(InvoiceFolder).garbage_mode().stream():
print(f"Deleted: {folder.system.id} – {folder.Title}")
14. Child objects (with_children)
.with_children() switches to a HOL query that returns each main object together with its child objects. The call returns an ECMModelQueryHolSync. .limit() must be set before execute() or stream() because HOL responses do not support pagination.
Each result is an ECMHolResult with:
-
.main— the main object (e.g. the folder) -
.children_of(ECMChildSpec(ChildModel))— list of child objects of that type
-
Sync
-
Async
from ecmind_blue_client.ecm.model import ECMChildSpec
results = (
ecm.dms.select(InvoiceFolder)
.where(InvoiceFolder.Year == 2024)
.with_children(ECMChildSpec(InvoiceDocument))
.limit(100)
.execute()
)
for r in results:
print(f"Folder {r.main.Title}:")
for doc in r.children_of(ECMChildSpec(InvoiceDocument)):
print(f" Document {doc.system.id}")
from ecmind_blue_client.ecm.model import ECMChildSpec
results = await (
ecm.dms.select(InvoiceFolder)
.where(InvoiceFolder.Year == 2024)
.with_children(ECMChildSpec(InvoiceDocument))
.limit(100)
.execute()
)
for r in results:
print(f"Folder {r.main.Title}:")
for doc in r.children_of(ECMChildSpec(InvoiceDocument)):
print(f" Document {doc.system.id}")
15. Parent objects (with_parents)
.with_parents() inverts the response structure: the outermost parent type (first spec) becomes the main object result.main. The originally queried object and all intermediate levels are accessible via .children_of().
Specs are passed from outermost to innermost (e.g. Folder first, then Register).
-
Sync
-
Async
from ecmind_blue_client.ecm.model import ECMChildSpec, ECMParentSpec
results = (
ecm.dms.select(InvoiceDocument)
.where(InvoiceDocument.Status == "Approved")
.with_parents(ECMParentSpec(InvoiceFolder), ECMParentSpec(InvoiceRegister))
.limit(50)
.execute()
)
for r in results:
folder = r.main # InvoiceFolder
register = r.children_of(ECMChildSpec(InvoiceRegister))[0]
doc = r.children_of(ECMChildSpec(InvoiceDocument))[0]
print(f"{folder.Title} → {register.Title} → Doc {doc.system.id}")
from ecmind_blue_client.ecm.model import ECMChildSpec, ECMParentSpec
results = await (
ecm.dms.select(InvoiceDocument)
.where(InvoiceDocument.Status == "Approved")
.with_parents(ECMParentSpec(InvoiceFolder), ECMParentSpec(InvoiceRegister))
.limit(50)
.execute()
)
for r in results:
folder = r.main
register = r.children_of(ECMChildSpec(InvoiceRegister))[0]
doc = r.children_of(ECMChildSpec(InvoiceDocument))[0]
print(f"{folder.Title} → {register.Title} → Doc {doc.system.id}")
16. Examples
16.1. Basic query with filter and sorting
-
Sync
-
Async
from ecmind_blue_client.ecm.model import ECMFolderModel, ECMField
class InvoiceFolder(ECMFolderModel):
_internal_name_ = "InvoiceFolder"
Title: ECMField[str]
Year: ECMField[int]
for folder in (
ecm.dms.select(InvoiceFolder)
.where(InvoiceFolder.Year >= 2020)
.order_by(InvoiceFolder.Year.DESC)
.stream()
):
print(folder.system.id, folder.Title)
from ecmind_blue_client.ecm.model import ECMFolderModel, ECMField
class InvoiceFolder(ECMFolderModel):
_internal_name_ = "InvoiceFolder"
Title: ECMField[str]
Year: ECMField[int]
async for folder in (
ecm.dms.select(InvoiceFolder)
.where(InvoiceFolder.Year >= 2020)
.order_by(InvoiceFolder.Year.DESC)
.stream()
):
print(folder.system.id, folder.Title)
16.2. Combined conditions (AND / OR)
-
Sync
-
Async
for folder in (
ecm.dms.select(InvoiceFolder)
.where(
(InvoiceFolder.Year >= 2020) & (InvoiceFolder.Year <= 2024),
InvoiceFolder.Title == "Invoice",
)
.stream()
):
print(folder.Title, folder.Year)
async for folder in (
ecm.dms.select(InvoiceFolder)
.where(
(InvoiceFolder.Year >= 2020) & (InvoiceFolder.Year <= 2024),
InvoiceFolder.Title == "Invoice",
)
.stream()
):
print(folder.Title, folder.Year)
16.3. Limit, offset and page size
-
Sync
-
Async
# At most 50 results, starting at position 100, in batches of 25 per server request
for folder in (
ecm.dms.select(InvoiceFolder)
.limit(50)
.offset(100)
.pagesize(25)
.stream()
):
print(folder.system.id)
async for folder in (
ecm.dms.select(InvoiceFolder)
.limit(50)
.offset(100)
.pagesize(25)
.stream()
):
print(folder.system.id)
16.4. Rights and audit metadata
-
Sync
-
Async
for folder in (
ecm.dms.select(InvoiceFolder)
.rights()
.base_params()
.stream()
):
print(folder.system.rights)
print(folder.system.base_params)
async for folder in (
ecm.dms.select(InvoiceFolder)
.rights()
.base_params()
.stream()
):
print(folder.system.rights)
print(folder.system.base_params)
16.5. Selective fields
Use .fields() to load only the specified fields from the server. This significantly reduces
the amount of data transferred when only a few fields are needed.
-
Sync
-
Async
for folder in (
ecm.dms.select(InvoiceFolder)
.fields(InvoiceFolder.Title, InvoiceFolder.Year)
.stream()
):
print(folder.Title, folder.Year)
# folder.OtherField would be None (not loaded)
async for folder in (
ecm.dms.select(InvoiceFolder)
.fields(InvoiceFolder.Title, InvoiceFolder.Year)
.stream()
):
print(folder.Title, folder.Year)
16.6. Querying the recycle bin
-
Sync
-
Async
# Only deleted objects
for folder in ecm.dms.select(InvoiceFolder).garbage_mode().stream():
print(folder.system.id, folder.Title)
async for folder in ecm.dms.select(InvoiceFolder).garbage_mode().stream():
print(folder.system.id, folder.Title)
16.7. Generic model (without a class definition)
When the object type is only known at runtime, a model can be created dynamically:
-
Sync
-
Async
from ecmind_blue_client.ecm.model import make_folder_model
InvoiceFolder = make_folder_model("InvoiceFolder")
for folder in ecm.dms.select(InvoiceFolder).stream():
print(folder.system.id, folder["Title"])
from ecmind_blue_client.ecm.model import make_folder_model
InvoiceFolder = make_folder_model("InvoiceFolder")
async for folder in ecm.dms.select(InvoiceFolder).stream():
print(folder.system.id, folder["Title"])
16.8. Combined query across document, register and folder
-
Sync
-
Async
from tests.models.Unittest_DMS import Unittest_DMS, Unittest_DMS_Register, Unittest_DMS_Document
for doc in (
ecm.dms.select(Unittest_DMS_Document)
.where(
Unittest_DMS_Document.StringField == "Invoice",
Unittest_DMS_Register.Name == "Incoming invoices",
Unittest_DMS.Name == "Supplier GmbH",
)
.stream()
):
print(doc.system.id, doc.Name)
from tests.models.Unittest_DMS import Unittest_DMS, Unittest_DMS_Register, Unittest_DMS_Document
async for doc in (
ecm.dms.select(Unittest_DMS_Document)
.where(
Unittest_DMS_Document.StringField == "Invoice",
Unittest_DMS_Register.Name == "Incoming invoices",
Unittest_DMS.Name == "Supplier GmbH",
)
.stream()
):
print(doc.system.id, doc.Name)
16.9. Search for a folder containing a matching child object
-
Sync
-
Async
from tests.models.Unittest_DMS import Unittest_DMS, Unittest_DMS_Document
for folder in (
ecm.dms.select(Unittest_DMS)
.where(
Unittest_DMS.Name == "Supplier GmbH",
Unittest_DMS_Document.StringField == "Invoice",
)
.stream()
):
print(folder.system.id, folder.Name)
from tests.models.Unittest_DMS import Unittest_DMS, Unittest_DMS_Document
async for folder in (
ecm.dms.select(Unittest_DMS)
.where(
Unittest_DMS.Name == "Supplier GmbH",
Unittest_DMS_Document.StringField == "Invoice",
)
.stream()
):
print(folder.system.id, folder.Name)