·
商品查询返回了数据,却包含范围外的商品,先检查搜索式是否被按预期解析。本文针对 GraphQL Admin API 的 products 查询,完成一次“诊断搜索式、修正 UTC 边界、验收小量结果”的只读排查。输入是时间范围和实际请求;输出是可解释的诊断记录与样本结果。
本文按 2026 年 10 月 4 日核对的 2026-10 文档编写。前提是现有应用已获商家授权,并具有所需的 read_products 权限;使用在线访问方式时还要考虑操作用户的权限。先确认现有授权,再执行下面的读取。参见 Product 权限要求和访问范围与商家授权说明。
先把时间范围写成可核对的搜索式
假设要检查 UTC 的 2026 年 10 月 1 日,约定范围为下界包含、上界不包含,即从 2026-10-01T00:00:00Z 到 2026-10-02T00:00:00Z。这是演示输入,不代表某个商店的实际数据。带时区的输入应先转换为 UTC,不能把本地零点直接加上 Z。
products 的搜索字段是 updated_at,响应里的商品字段则是 updatedAt。搜索式中的日期值要加引号,两个比较条件以空格连接。排序采用与筛选字段相配的 UPDATED_AT;默认排序键是 ID。这些名称分别见 products 的 updated_at 与 sortKey 定义、ProductSortKeys和日期比较语法。
updated_at:>='2026-10-01T00:00:00Z' updated_at:<'2026-10-02T00:00:00Z'
在实际请求上开启搜索诊断
在现有授权请求层向 /admin/api/2026-10/graphql.json 发送以下查询和变量,并加入请求头 Shopify-Search-Query-Debug: 1。这个头用于取得搜索诊断;要检查实际发送的头和变量,而不是仅检查客户端的配置对象。官方示例见搜索诊断请求头与响应。
query ProductWindow($filter: String!, $after: String) {
products(first: 5, after: $after, query: $filter,
sortKey: UPDATED_AT, reverse: false) {
nodes { id updatedAt }
pageInfo { hasNextPage endCursor }
}
}
{
"filter": "updated_at:>='2026-10-01T00:00:00Z' updated_at:<'2026-10-02T00:00:00Z'",
"after": null
}
首次请求的 after 为 null,first: 5 只用于小量检查。记录响应的 X-Shopify-API-Version,确认实际处理版本与预期一致;Shopify 对不再支持的请求版本可能回退到受支持版本,不能只看 URL。参见版本响应头说明。
先看 warnings,再逐项核对 parsed
在响应的 extensions.search 中找到对应 products 路径的记录,并核对其 query 与本次发送的筛选式。随后检查 warnings 和 parsed。官方诊断示例包含 path、query、parsed、warnings;无效搜索字段会被忽略,可能造成结果范围扩大。字段是否可用应查当前资源定义,不能将其他资源的筛选字段直接搬来。参见搜索解析与无效字段警告。
- 出现无效字段等警告时,保存原请求和警告,修正搜索字段后重新请求。此时返回了商品也不能证明筛选生效。
- 没有诊断记录时,检查实际请求是否携带 debug 头、响应扩展是否被中间层丢弃,以及请求路径和变量是否对应本次查询。
- 有
parsed且没有返回警告后,仍需阅读解析结果:字段应是updated_at,下界应包含、上界应排除,两个条件应共同约束该范围。
本文查询没有别名,因此下面的辅助函数只匹配路径 ["products"]。若查询改用别名,应根据该请求的实际诊断路径调整匹配规则。不要把多个路径的诊断合并成一份成功结论。
用小函数生成边界并保留人工验收关口
以下 Python 代码只处理带时区日期与诊断记录,不发送 HTTP。utc_filter 生成同一 UTC 范围;inspect_search 拒绝缺失、错配、有警告或有顶层错误的输入。返回 REVIEW_PARSED_SCOPE 的含义是“可以开始人工核对 parsed”,并非自动确认 Shopify 已正确执行所有搜索条件。
"""Offline helpers for one bounded products search. No HTTP client."""
from datetime import datetime, timezone
def utc_filter(lower, upper):
def parse(value):
stamp = datetime.fromisoformat(value.replace("Z", "+00:00"))
if "T" not in value or stamp.tzinfo is None:
raise ValueError("timezone-bearing datetime required")
return stamp.astimezone(timezone.utc)
start, end = parse(lower), parse(upper)
if start >= end:
raise ValueError("lower boundary must precede upper boundary")
fmt = lambda value: value.isoformat().replace("+00:00", "Z")
return f"updated_at:>='{fmt(start)}' updated_at:<'{fmt(end)}'"
def inspect_search(payload, expected_filter):
if not isinstance(payload, dict) or payload.get("errors"):
return "CHECK_RESPONSE_ERRORS", None
ext = payload.get("extensions")
diagnostics = ext.get("search") if isinstance(ext, dict) else None
if not isinstance(diagnostics, list):
return "NO_SEARCH_DIAGNOSTICS", None
matches = [entry for entry in diagnostics if isinstance(entry, dict)
and entry.get("path") == ["products"]]
if len(matches) != 1:
return "AMBIGUOUS_OR_MISSING_PATH", None
entry = matches[0]
if entry.get("query") != expected_filter:
return "FILTER_MISMATCH", None
warnings = entry.get("warnings", [])
if not isinstance(warnings, list):
return "UNCONFIRMED_WARNING_SHAPE", None
if warnings:
return "SEARCH_WARNINGS", warnings
if not isinstance(entry.get("parsed"), dict) or not entry["parsed"]:
return "NO_PARSED_DIAGNOSTIC", None
return "REVIEW_PARSED_SCOPE", entry["parsed"]
调用 inspect_search(payload, filter_value) 前,应由现有请求层检查 HTTP 响应、JSON 解码与实际 API 版本。这里没有实现 Shopify 搜索解析器,也不根据一个固定的自造 AST 形状判断线上语义。若还需检查单个商品的字段类型、空值和错误响应,可参照商品响应契约与字段验收。
用小量只读结果完成这次排查
搜索诊断通过人工核对后,逐个检查返回的 id 与 updatedAt,将时间转换为 UTC,再比较是否落在所约定的范围内。如果有已知更新时间的测试商品,可在受控环境中核对边界附近的对象;本例没有在商家店铺执行该测试。
- 把最终查询、变量、实际版本、诊断记录与样本 ID 保存在同一次排查记录中,避免拿旧响应解释新筛选式。
hasNextPage为true时,五条样本不能当作完整范围。需要继续读取时,维持查询条件与排序,把endCursor用作下一页的after;修改筛选式后从首页面重新检查。连续读取与断点持久化另见分页和安全断点示例。- 若出现范围外对象,保留该对象时间、原始诊断和请求变量,先确认 UTC 转换与实际解析范围,再决定下一步排查。
本轮配套的离线合成用例已检查带偏移日期转 UTC、无时区输入拒绝、反向范围拒绝、诊断缺失、查询错配与警告拦截。诊断测试使用人工构造的数据,不代表 Shopify 实际返回的 parsed 树;没有向商家 API 发请求。样本验收用于判断这一次搜索式排查能否结束,不能保证持续变化的商品集合已形成一致快照。
WESWOO — Shopify Storefront Development
We help Chinese brands expand internationally with storefront development and Shopify Plus integration services, supporting their cross-border commerce operations.
- Shopify storefront branding
- International UI design
- Multichannel social media marketing