search-assets

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ImageKit Search Queries (
searchQuery
)

ImageKit 搜索查询(
searchQuery

client.assets.list({ searchQuery })
takes a Lucene-like filter string. A good query is the difference between one precise API call and paging through everything. This skill is the cheatsheet for building that string.
When user requests "find Nike brand images", here brand could be a custom metadata field, i.e.
"customMetadata.brand"
. So it is always recommended to first list the custom metadata fields available so that correct
searchQuery
can be constructed. You can use
client.customMetadataFields.list()
to get the list of custom metadata fields and their types.
client.assets.list({ searchQuery })
接受类Lucene风格的过滤字符串。一个精准的查询能让你通过一次API调用得到结果,而非翻页遍历所有内容。本技能就是构建该字符串的速查表。
当用户请求“查找Nike品牌图片”时,这里的“brand”可能是一个自定义元数字段,即
"customMetadata.brand"
。因此,始终建议先列出可用的自定义元数字段,以便构建正确的
searchQuery
。你可以使用
client.customMetadataFields.list()
获取自定义元数字段列表及其类型。

Syntax

语法

  • Operators:
    =
    :
    <
    <=
    >
    >=
    IN
    NOT IN
    NOT =
    HAS
    EXISTS
    NOT EXISTS
  • Combine:
    AND
    ,
    OR
    . Group:
    ( ... )
  • Quoting: string values in
    "double quotes"
    ; numbers and booleans (
    true
    /
    false
    ) unquoted;
    customMetadata
    /
    embeddedMetadata
    field names must be quoted, e.g.
    "customMetadata.brand"
    .
  • :
    = begins-with / within-subfolders.
    =
    = exact.
    HAS
    = case-insensitive full-text (tokenized).
  • 运算符:
    =
    :
    <
    <=
    >
    >=
    IN
    NOT IN
    NOT =
    HAS
    EXISTS
    NOT EXISTS
  • 组合:
    AND
    OR
    分组:
    ( ... )
  • 引号规则: 字符串值需用
    "双引号"
    包裹;数字和布尔值(
    true
    /
    false
    )无需引号;
    customMetadata
    /
    embeddedMetadata
    字段名必须加引号,例如
    "customMetadata.brand"
  • :
    = 前缀匹配/包含子文件夹。
    =
    = 精确匹配。
    HAS
    = 不区分大小写的全文(分词)匹配。

Field reference

字段参考

FieldOperatorsValue notes
name
=
:
IN
NOT =
NOT IN
HAS
String.
=
exact (case-sensitive),
:
begins-with,
HAS
case-insensitive full-text
tags
IN
NOT IN
HAS
EXISTS
NOT EXISTS
Array. Matches both
tags
and
AITags
type
=
IN
NOT =
NOT IN
"file"
|
"file-version"
|
"folder"
id
=
IN
NOT =
NOT IN
fileId or folderId string
createdAt
/
updatedAt
=
<
<=
>
>=
IN
NOT =
NOT IN
ISO 8601 (
"2020-01-01"
,
"2020-01-01T12:12:12"
) or relative (
"1h"
"2d"
"3w"
"4m"
"1y"
)
width
/
height
=
<
<=
>
>=
IN
NOT =
NOT IN
Numeric px. Images only
size
=
<
<=
>
>=
IN
NOT =
NOT IN
Bytes (
1024
) or string (
"1mb"
,
"10kb"
)
format
=
IN
"jpg"
"png"
"webp"
"gif"
"svg"
"avif"
"pdf"
"mp4"
private
/
published
/
transparency
=
Boolean, unquoted:
true
/
false
createdBy
=
IN
NOT =
NOT IN
Uploader email string
path
=
:
IN
NOT =
NOT IN
=
exact folder only;
:
folder + subfolders
"customMetadata.<field>"
type-dependent (
=
:
IN
HAS
<
>
EXISTS
…)
Quote the field name. Operators follow the field's schema type
"embeddedMetadata.<field>"
type-dependentQuote the field name.
Keywords
uses
IN
/
EXISTS
;
DateTimeOriginal
uses date ops;
LocationTaken
supports geo (
"40,100 5km"
)
字段运算符值说明
name
=
:
IN
NOT =
NOT IN
HAS
字符串。
=
精确匹配(区分大小写),
:
前缀匹配,
HAS
不区分大小写全文匹配
tags
IN
NOT IN
HAS
EXISTS
NOT EXISTS
数组。同时匹配
tags
AITags
type
=
IN
NOT =
NOT IN
"file"
|
"file-version"
|
"folder"
id
=
IN
NOT =
NOT IN
文件ID或文件夹ID字符串
createdAt
/
updatedAt
=
<
<=
>
>=
IN
NOT =
NOT IN
ISO 8601格式(
"2020-01-01"
,
"2020-01-01T12:12:12"
)或相对时间(
"1h"
"2d"
"3w"
"4m"
"1y"
width
/
height
=
<
<=
>
>=
IN
NOT =
NOT IN
数值(像素)。仅适用于图片
size
=
<
<=
>
>=
IN
NOT =
NOT IN
字节数(
1024
)或字符串格式(
"1mb"
,
"10kb"
format
=
IN
"jpg"
"png"
"webp"
"gif"
"svg"
"avif"
"pdf"
"mp4"
private
/
published
/
transparency
=
布尔值,无需引号:
true
/
false
createdBy
=
IN
NOT =
NOT IN
上传者邮箱字符串
path
=
:
IN
NOT =
NOT IN
=
仅精确匹配文件夹;
:
匹配文件夹及其子文件夹
"customMetadata.<field>"
依赖类型(
=
:
IN
HAS
<
>
EXISTS
…)
字段名需加引号。运算符遵循字段的 schema 类型
"embeddedMetadata.<field>"
依赖类型字段名需加引号。
Keywords
使用
IN
/
EXISTS
DateTimeOriginal
使用日期运算符;
LocationTaken
支持地理范围(
"40,100 5km"

Query examples

查询示例

text
name = "red-dress.jpg"                                  exact name (case-sensitive)
name : "red-dress"                                      name begins with red-dress
name HAS "red dress"                                    full-text: contains red AND dress (any case)
id = "64fb1c2d8a7b4c1234567890"                         single file/folder by id

createdAt > "7d"                                        uploaded in last 7 days
createdAt < 2020-01-01                                  uploaded before Jan 1 2020 (00:00 UTC)
updatedAt >= "2024-06-01T00:00:00"                      modified on/after a timestamp
createdAt > "7d" AND size > "2mb"                       recent AND large

size <= "1mb"                                           1MB or smaller
width > 500 AND height > 500                            at least 500x500 (images)
format = "png"                                          PNG files
format IN ["jpg", "webp"]                               JPG or WebP

tags IN ["sale", "summer"]                              has sale OR summer (tags or AITags)
tags NOT IN ["draft"]                                   excludes draft
tags HAS "sale"                                         full-text token match (sales, summer-sale…)
tags EXISTS                                             has at least one tag
tags NOT EXISTS                                         untagged files

type = "file"                                           files only
private = true                                          private files
published = false                                       drafts / unpublished
transparency = true                                     images with an alpha layer

path = "/sales-banner/"                                 exactly this folder, no subfolders
path : "/sales-banner/"                                 this folder AND its subfolders
format = "png" AND path : "/sales-banner/"              PNGs under a folder tree

"customMetadata.category" IN ["clothing", "accessories"]
"customMetadata.rating" > 4.3
"customMetadata.active" = true
"customMetadata.description" HAS "red"
"embeddedMetadata.DateTimeOriginal" > "1y"
"embeddedMetadata.LocationTaken" = "40,100 5km"

(size < "1mb" AND width > 500) OR (tags IN ["summer-sale", "banner"])
text
name = "red-dress.jpg"                                  exact name (case-sensitive)
name : "red-dress"                                      name begins with red-dress
name HAS "red dress"                                    full-text: contains red AND dress (any case)
id = "64fb1c2d8a7b4c1234567890"                         single file/folder by id

createdAt > "7d"                                        uploaded in last 7 days
createdAt < 2020-01-01                                  uploaded before Jan 1 2020 (00:00 UTC)
updatedAt >= "2024-06-01T00:00:00"                      modified on/after a timestamp
createdAt > "7d" AND size > "2mb"                       recent AND large

size <= "1mb"                                           1MB or smaller
width > 500 AND height > 500                            at least 500x500 (images)
format = "png"                                          PNG files
format IN ["jpg", "webp"]                               JPG or WebP

tags IN ["sale", "summer"]                              has sale OR summer (tags or AITags)
tags NOT IN ["draft"]                                   excludes draft
tags HAS "sale"                                         full-text token match (sales, summer-sale…)
tags EXISTS                                             has at least one tag
tags NOT EXISTS                                         untagged files

type = "file"                                           files only
private = true                                          private files
published = false                                       drafts / unpublished
transparency = true                                     images with an alpha layer

path = "/sales-banner/"                                 exactly this folder, no subfolders
path : "/sales-banner/"                                 this folder AND its subfolders
format = "png" AND path : "/sales-banner/"              PNGs under a folder tree

"customMetadata.category" IN ["clothing", "accessories"]
"customMetadata.rating" > 4.3
"customMetadata.active" = true
"customMetadata.description" HAS "red"
"embeddedMetadata.DateTimeOriginal" > "1y"
"embeddedMetadata.LocationTaken" = "40,100 5km"

(size < "1mb" AND width > 500) OR (tags IN ["summer-sale", "banner"])

Custom metadata — discover field names first

自定义元数据——先获取字段名

"customMetadata.<field>"
only matches fields defined in your media library's custom-metadata schema, and the allowed operators depend on the field's type (Text/Textarea →
=
:
IN
HAS
; Number/Date →
<
<=
>
>=
; Boolean →
=
; Single/MultiSelect →
IN
). If the user's request mentions a custom attribute (brand, category, rating, SKU, season…), list the schema first to get the exact field name and type, then build the query:
typescript
const fields = await client.customMetadataFields.list();
// each: { id, name, label, schema: { type: 'Text' | 'Number' | 'Date' | 'Boolean' | 'SingleSelect' | 'MultiSelect', ... } }
const brand = fields.find((f) => f.name === 'brand' || f.label === 'Brand');
if (!brand) throw new Error('No "brand" custom metadata field is defined');

const result = await client.assets.list({
  searchQuery: 'type = "file" AND "customMetadata.brand" = "nike"',
  limit: 100,
});
Quote the whole
"customMetadata.<field>"
token.
"embeddedMetadata.<field>"
(e.g.
Keywords
,
DateTimeOriginal
,
LocationTaken
) works the same way, but embedded fields are read from the file itself and are not user-defined — no schema lookup needed.
"customMetadata.<field>"
仅匹配媒体库自定义元数据 schema 中定义的字段,且允许的运算符取决于字段类型(文本/文本域 →
=
:
IN
HAS
;数字/日期 →
<
<=
>
>=
;布尔值 →
=
;单选/多选 →
IN
)。如果用户请求中提到自定义属性(品牌、分类、评分、SKU、季节…),先列出schema以获取准确的字段名和类型,再构建查询:
typescript
const fields = await client.customMetadataFields.list();
// each: { id, name, label, schema: { type: 'Text' | 'Number' | 'Date' | 'Boolean' | 'SingleSelect' | 'MultiSelect', ... } }
const brand = fields.find((f) => f.name === 'brand' || f.label === 'Brand');
if (!brand) throw new Error('No "brand" custom metadata field is defined');

const result = await client.assets.list({
  searchQuery: 'type = "file" AND "customMetadata.brand" = "nike"',
  limit: 100,
});
需将整个
"customMetadata.<field>"
标记用引号包裹。
"embeddedMetadata.<field>"
(例如
Keywords
DateTimeOriginal
LocationTaken
)的用法相同,但嵌入字段是从文件本身读取的,并非用户定义——无需查找schema。

TypeScript usage

TypeScript 使用方法

client.assets.list()
returns
(File | Folder)[]
. How you get a typed result depends on whether you use
searchQuery
:
No
searchQuery
— pass
type
to get a typed array directly (no narrowing):
typescript
const files = await client.assets.list({ type: 'file', path: '/uploads', limit: 100 });
//    ^ File[] — fileId, size, url are all available without narrowing
With
searchQuery
— the API IGNORES the
type
/
tags
/
name
params
, so the result stays the
(File | Folder)[]
union. Put the type filter inside the query string and narrow each item:
typescript
const result = await client.assets.list({
  searchQuery: 'type = "file" AND createdAt >= "7d" AND size > "2mb"',
  limit: 100,
});
const files = [];
for (const item of result) {
  if (item.type === 'file') {
    files.push({ name: item.name, fileId: item.fileId, size: item.size });
  }
}
Accessing ANY member-specific property. On the bare
File | Folder
union you can only read properties common to both (
name
,
type
,
createdAt
,
updatedAt
,
customMetadata
). Every other property —
filePath
,
url
,
fileId
,
size
,
width
,
tags
… (File-only) and
folderPath
(Folder-only) — exists on just one member and won't compile until you narrow
item
to a single concrete type. Narrow once with an
if
/
else
, then access anything inside that block. Key subtlety:
File.type
is
'file' | 'file-version'
while
Folder.type
is only
'folder'
, so branch on
type === 'folder'
— its else branch is guaranteed
File
(covers plain files and file-versions):
typescript
const rows = result.map((item) => {
  if (item.type === 'folder') {
    return { name: item.name, kind: 'folder', path: item.folderPath }; // item: Folder
  }
  return { name: item.name, kind: 'file', path: item.filePath, size: item.size, url: item.url }; // item: File
});
Only reading File fields? A single
if (item.type === 'file') { … }
guard is enough — inside it
item
is a fully-typed
File
, so any File property is available.
Full-text search — always pair
HAS
with
DESC_RELEVANCE
:
typescript
const result = await client.assets.list({
  searchQuery: 'name HAS "red dress"',
  sort: 'DESC_RELEVANCE',
  limit: 20,
});
Paginate with
skip
/
limit
(max 1000 per page):
typescript
for (let skip = 0; ; skip += 100) {
  const page = await client.assets.list({
    searchQuery: 'type = "file" AND tags IN ["sale", "summer"]',
    skip,
    limit: 100,
  });
  if (!page.length) break;
  for (const item of page) {
    if (item.type === 'file') {
      // item narrowed to File
    }
  }
}
client.assets.list()
返回
(File | Folder)[]
。如何获取类型化结果取决于是否使用
searchQuery
不使用
searchQuery
——传入
type
直接获取类型化数组(无需类型收窄):
typescript
const files = await client.assets.list({ type: 'file', path: '/uploads', limit: 100 });
//    ^ File[] — fileId、size、url等属性无需类型收窄即可访问
使用
searchQuery
——API会忽略
type
/
tags
/
name
参数
,因此结果仍为
(File | Folder)[]
联合类型。需将类型过滤条件放入查询字符串中,再对每个条目进行类型收窄:
typescript
const result = await client.assets.list({
  searchQuery: 'type = "file" AND createdAt >= "7d" AND size > "2mb"',
  limit: 100,
});
const files = [];
for (const item of result) {
  if (item.type === 'file') {
    files.push({ name: item.name, fileId: item.fileId, size: item.size });
  }
}
访问特定成员的属性。
File | Folder
联合类型中,只能读取两者共有的属性(
name
type
createdAt
updatedAt
customMetadata
)。其他所有属性——
filePath
url
fileId
size
width
tags
…(仅File拥有)和
folderPath
(仅Folder拥有)——仅属于其中一个类型,必须先对
item
进行类型收窄才能编译通过。用
if
/
else
进行一次类型收窄,然后在代码块内访问任意属性。关键细节:
File.type
'file' | 'file-version'
,而
Folder.type
仅为
'folder'
,因此通过
type === 'folder'
分支——其else分支必然是
File
(涵盖普通文件和文件版本):
typescript
const rows = result.map((item) => {
  if (item.type === 'folder') {
    return { name: item.name, kind: 'folder', path: item.folderPath }; // item: Folder
  }
  return { name: item.name, kind: 'file', path: item.filePath, size: item.size, url: item.url }; // item: File
});
仅需读取File属性?只需
if (item.type === 'file') { … }
即可——代码块内
item
为完全类型化的
File
,可访问任何File属性。
全文搜索——务必将
HAS
DESC_RELEVANCE
配合使用:
typescript
const result = await client.assets.list({
  searchQuery: 'name HAS "red dress"',
  sort: 'DESC_RELEVANCE',
  limit: 20,
});
使用
skip
/
limit
分页(每页最多1000条):
typescript
for (let skip = 0; ; skip += 100) {
  const page = await client.assets.list({
    searchQuery: 'type = "file" AND tags IN ["sale", "summer"]',
    skip,
    limit: 100,
  });
  if (!page.length) break;
  for (const item of page) {
    if (item.type === 'file') {
      // item 已收窄为File类型
    }
  }
}

Gotchas

注意事项

  • searchQuery
    overrides params.
    When
    searchQuery
    is present, the top-level
    type
    ,
    tags
    , and
    name
    params have NO effect — express those filters inside the query string instead (e.g.
    type = "file"
    ).
  • Narrow with
    for...of
    +
    if
    , not
    .filter((i): i is File => ...)
    .
    In the Deno/MCP sandbox the global
    File
    (Web API) shadows the SDK's
    File
    type, so the type predicate fails to compile. Use
    for (const item of result) { if (item.type === 'file') { … } }
    .
  • Only common fields exist on the bare
    File | Folder
    union.
    name
    ,
    type
    ,
    createdAt
    ,
    updatedAt
    ,
    customMetadata
    are shared; everything else (
    filePath
    ,
    url
    ,
    fileId
    ,
    size
    ,
    width
    ,
    tags
    ,
    folderPath
    …) is member-specific and needs narrowing first. Never reach for a property before narrowing.
  • Branch on
    type === 'folder'
    to split the union cleanly.
    File.type
    is
    'file' | 'file-version'
    ;
    Folder.type
    is only
    'folder'
    . So
    type === 'file'
    catches plain files but leaves the else branch as
    File | Folder
    , whereas
    type === 'folder'
    gives
    Folder
    in the
    if
    and a guaranteed
    File
    in the
    else
    .
  • name
    =
    /
    :
    are case-sensitive; use
    HAS
    for case-insensitive matching.
  • tags
    queries search both
    tags
    and
    AITags
    .
  • HAS
    tokenizes on spaces/punctuation; the last token matches as a prefix (
    "red"
    matches
    redwoods
    ). Pair with
    sort: 'DESC_RELEVANCE'
    .
  • Booleans (
    private
    ,
    published
    ,
    transparency
    ) are unquoted; everything string-valued is quoted.
  • width
    /
    height
    /
    transparency
    apply to images only.
  • searchQuery
    会覆盖参数。
    当存在
    searchQuery
    时,顶层的
    type
    tags
    name
    参数无效——需将这些过滤条件放入查询字符串中(例如
    type = "file"
    )。
  • 使用
    for...of
    +
    if
    进行类型收窄,而非
    .filter((i): i is File => ...)
    在Deno/MCP沙箱中,全局
    File
    (Web API)会遮蔽SDK的
    File
    类型,因此类型断言无法编译。请使用
    for (const item of result) { if (item.type === 'file') { … } }
  • 仅共有属性存在于
    File | Folder
    联合类型中。
    name
    type
    createdAt
    updatedAt
    customMetadata
    是共享属性;其他所有属性(
    filePath
    url
    fileId
    size
    width
    tags
    folderPath
    …)都是特定成员的属性,需要先进行类型收窄。在类型收窄前切勿访问这些属性。
  • 通过
    type === 'folder'
    分支可清晰拆分联合类型。
    File.type
    'file' | 'file-version'
    Folder.type
    仅为
    'folder'
    。因此
    type === 'file'
    仅匹配普通文件,else分支仍为
    File | Folder
    ,而
    type === 'folder'
    会在
    if
    分支得到
    Folder
    ,else分支必然是
    File
  • name
    =
    /
    :
    运算符区分大小写;如需不区分大小写匹配,请使用
    HAS
  • tags
    查询会同时搜索**
    tags
    AITags
    **。
  • HAS
    会按空格/标点分词;最后一个分词会作为前缀匹配(
    "red"
    会匹配
    redwoods
    )。需配合
    sort: 'DESC_RELEVANCE'
    使用。
  • 布尔值(
    private
    published
    transparency
    )无需引号;所有字符串值都需加引号。
  • width
    /
    height
    /
    transparency
    仅适用于图片。