Recipe: real-world search patterns
Recipe: real-world search patterns
Recipe: real-world search patterns
Prompt exampleFind the folder's contents, look up one asset by id, list only the top-level folders, return just the display names, page through a large result set, and resolve a language_id from the Languages content definition.
search is the most-used call. These are common patterns, expressed against the search
component. All are read-only, Class A — to confine, scope on parentId.
The endpoint is POST /api/{admin|portal}/search, chosen by the session's apiType. Both SDKs
expose the full 16-parameter surface (free-text, filters, sort, paging, field-select, plus the
advanced modes below); there is no SDK ceiling — older 6-param docs were stale.
Key facts (see reference/return-shapes.md + enums.md)
- The result is
{items, totalItemCount, hasItems}. Empty results return the object withitems: []in both languages; guard only againstNone/null. - A result's name/parent live under
item["identifiers"], not at the top level. - Filters are
{fieldName, operator, values}; AND-combined by default.operatorisEquals(the most common),Contains,Prefix,NotEquals, … (seeenums.md). offsetis zero-based; page untillen(items) < sizeor you covertotalItemCount.
Python
# component: search (def search(sdk, query=None, filters=None, sort_fields=None,
# size=None, offset=None, search_result_fields=None, *,
# similar_asset_id=None, min_score=None, use_llm_search=None,
# search_text_fields=None, filter_binder=None, ...))
def folder_contents(sdk, folder_id, size=100):
"""Direct children of a folder — the parentId-Equals pattern."""
flt = [{"fieldName": "parentId", "operator": "Equals", "values": folder_id}]
return (search(sdk, filters=flt, size=size) or {}).get("items", [])
def find_by_id(sdk, asset_id):
"""Fetch one record by exact id (the portal id-lookup pattern)."""
flt = [{"fieldName": "uuidSearchField", "operator": "Equals", "values": asset_id}]
items = (search(sdk, filters=flt) or {}).get("items", [])
return items[0] if items else None
def top_level_folders(sdk, content_definition_id):
"""Only the roots of the tree, for one content type."""
flt = [
{"fieldName": "contentDefinitionId", "operator": "Equals", "values": content_definition_id},
{"fieldName": "assetType", "operator": "Equals", "values": 1},
{"fieldName": "topLevelFolder", "operator": "Equals", "values": "true"},
]
return (search(sdk, filters=flt, size=100) or {}).get("items", [])
def names_only(sdk, folder_id):
"""Return just display names — select fields with dotted paths."""
flt = [{"fieldName": "parentId", "operator": "Equals", "values": folder_id}]
fields = [{"name": "identifiers.displayName"}, {"name": "identifiers.assetType"}]
res = search(sdk, filters=flt, search_result_fields=fields, size=100) or {}
return [i.get("identifiers", {}).get("displayName") for i in res.get("items", [])]
def iter_all(sdk, filters, page_size=100):
"""Yield every item across pages (offset is zero-based)."""
offset = 0
while True:
page = search(sdk, filters=filters, size=page_size, offset=offset) or {}
items = page.get("items", [])
for item in items:
yield item
if len(items) < page_size:
return
offset += 1 # offset is in PAGES (page index), not records
def sorted_by_name(sdk, folder_id):
"""Folder contents sorted A→Z by display name (sortType, not sortOrder)."""
flt = [{"fieldName": "parentId", "operator": "Equals", "values": folder_id}]
srt = [{"fieldName": "displayName", "sortType": "Ascending"}]
return (search(sdk, filters=flt, sort_fields=srt, size=100) or {}).get("items", [])
def find_language_id(sdk, languages_content_definition_id, display_name):
"""Resolve a language_id for update_asset_language via the Languages content def.
There is no list-languages SDK verb; search the Languages content definition
and read the matching record's id. languages_content_definition_id is the
stable per-deployment content definition for languages (discover once, reuse).
"""
flt = [{"fieldName": "contentDefinitionId", "operator": "Equals",
"values": languages_content_definition_id}]
items = (search(sdk, filters=flt, size=200) or {}).get("items", [])
for item in items:
if (item.get("identifiers") or {}).get("displayName") == display_name:
return item.get("id")
return NoneJavaScript
// component: search(sdk, query, filters, sortFields, size, offset, searchResultFields, opts)
// opts = { similarAssetId, minScore, useLlmSearch, searchTextFields, filterBinder, ... }
export async function folderContents(sdk, folderId, size = 100) {
const flt = [{ fieldName: "parentId", operator: "Equals", values: folderId }];
const res = await search(sdk, null, flt, null, size);
return res ? res.items : []; // res is the object (items: []) when empty; null only on failure
}
export async function findById(sdk, assetId) {
const flt = [{ fieldName: "uuidSearchField", operator: "Equals", values: assetId }];
const res = await search(sdk, null, flt);
return res && res.items.length ? res.items[0] : null;
}
export async function topLevelFolders(sdk, contentDefinitionId) {
const flt = [
{ fieldName: "contentDefinitionId", operator: "Equals", values: contentDefinitionId },
{ fieldName: "assetType", operator: "Equals", values: 1 },
{ fieldName: "topLevelFolder", operator: "Equals", values: "true" },
];
const res = await search(sdk, null, flt, null, 100);
return res ? res.items : [];
}
export async function namesOnly(sdk, folderId) {
const flt = [{ fieldName: "parentId", operator: "Equals", values: folderId }];
const fields = [{ name: "identifiers.displayName" }, { name: "identifiers.assetType" }];
const res = await search(sdk, null, flt, null, 100, null, fields);
return res ? res.items.map((i) => i.identifiers?.displayName) : [];
}
export async function findLanguageId(sdk, languagesContentDefinitionId, displayName) {
// Resolve a languageId for updateAssetLanguage via the Languages content def.
// No list-languages SDK verb; search the Languages content definition instead.
const flt = [{ fieldName: "contentDefinitionId", operator: "Equals",
values: languagesContentDefinitionId }];
const res = await search(sdk, null, flt, null, 200);
const items = res ? res.items : [];
const match = items.find((i) => i.identifiers?.displayName === displayName);
return match ? match.id : null;
}Advanced search
Operator and field-bucket tables are in reference/enums.md.
Python
def find_similar(sdk, asset_id, min_score=0.65, size=20):
"""Vector find-similar: items most like `asset_id`. Ignores query/offset;
needs vector search enabled (else an empty result with a 'not enabled' message)."""
return (search(sdk, similar_asset_id=asset_id, min_score=min_score, size=size)
or {}).get("items", [])
def llm_search(sdk, question, size=20):
"""LLM/deep semantic search over a natural-language query (segment-level for video)."""
return (search(sdk, query=question, use_llm_search=True, size=size)
or {}).get("items", [])
def search_transcripts(sdk, phrase, size=50):
"""Scope free-text to subtitles/transcripts only (see SearchTextFields in enums.md)."""
return (search(sdk, query=phrase, search_text_fields=["Transcripts"], size=size)
or {}).get("items", [])
def created_in_range(sdk, folder_id, start_utc, end_utc):
"""Range operators on a date field (UTC YYYY-MM-DDTHH:MM:SS.SSSZ); AND-combined."""
flt = [
{"fieldName": "parentId", "operator": "Equals", "values": folder_id},
{"fieldName": "createdDate", "operator": "GreaterThanEquals", "values": start_utc},
{"fieldName": "createdDate", "operator": "LessThan", "values": end_utc},
]
return (search(sdk, filters=flt, size=100) or {}).get("items", [])
def name_prefix_or_substring(sdk, folder_id, term):
"""Non-Equals string ops: Prefix (starts-with) + Contains (token match), OR-combined.
Use filter_binder=1 so the two name predicates are ORed instead of ANDed."""
flt = [
{"fieldName": "displayName", "operator": "Prefix", "values": term},
{"fieldName": "displayName", "operator": "Contains", "values": term},
]
return (search(sdk, filters=flt, filter_binder=1, size=100) or {}).get("items", [])
def exact_name_or_missing(sdk, name):
"""Exact (case-sensitive) match via the .keyword sub-field; also keep records that
have no displayName at all (includeNull)."""
flt = [{"fieldName": "displayName.keyword", "operator": "Equals",
"values": name, "includeNull": True}]
return (search(sdk, filters=flt, size=100) or {}).get("items", [])
def distinct_videos_with_clips(sdk, query, size=50):
"""Collapse duplicates on masterId, return clip/segment rows, skip the (costly) total,
and compute signed URLs only for the preview field."""
return (search(sdk, query=query, size=size,
distinct_on_field_name="masterId",
include_video_clips=True,
full_url_field_names=["previewImageUrl"],
exclude_total_record_count=True) or {}).get("items", [])JavaScript
// Advanced options ride on the trailing opts object; the core positional args are unchanged.
export async function findSimilar(sdk, assetId, minScore = 0.65, size = 20) {
const res = await search(sdk, null, null, null, size, null, null,
{ similarAssetId: assetId, minScore });
return res ? res.items : [];
}
export async function llmSearch(sdk, question, size = 20) {
const res = await search(sdk, question, null, null, size, null, null,
{ useLlmSearch: true });
return res ? res.items : [];
}
export async function searchTranscripts(sdk, phrase, size = 50) {
const res = await search(sdk, phrase, null, null, size, null, null,
{ searchTextFields: ["Transcripts"] });
return res ? res.items : [];
}
export async function namePrefixOrSubstring(sdk, term) {
// OR the two name predicates with filterBinder = 1 (0/unset = AND).
const flt = [
{ fieldName: "displayName", operator: "Prefix", values: term },
{ fieldName: "displayName", operator: "Contains", values: term },
];
const res = await search(sdk, null, flt, null, 100, null, null, { filterBinder: 1 });
return res ? res.items : [];
}
export async function distinctVideosWithClips(sdk, query, size = 50) {
const res = await search(sdk, query, null, null, size, null, null, {
distinctOnFieldName: "masterId",
includeVideoClips: true,
fullUrlFieldNames: ["previewImageUrl"],
excludeTotalRecordCount: true,
});
return res ? res.items : [];
}Operator gotcha: range operators (
LessThan/GreaterThan/…) andPrefixare not valid against an array ofvalues— the API returns 400. Use a single value per range predicate (combine with multiple filters as above).
Notes
parentId Equalsis the workhorse for "what's in this folder?";uuidSearchField Equalsis the workhorse for "give me exactly this id".- Newly created/uploaded assets are searchable only after indexing — there is a short lag
before they appear in results, so poll (or read directly via
get/list_childrenwhen you already hold the id). - Use
sortType(Ascending/Descending), notsortOrder. - Resolving a
language_id: there is no list-languages SDK verb. Filter search on the Languages content definition (contentDefinitionId Equals <languages-content-def-id>) and read the matching item'sid— this is the idupdate_asset_languageexpects. The Languages content definition id is stable per deployment; discover it once and reuse it.
