如何在Sanity.io中按指定slug筛选查询单条匹配数据
Sanity GROQ按slug筛选单条文档实现方案
问题场景
现有如下游戏数据集:
[ { "name": "Gates of Olympus", "slug": { "_type": "slug", "current": "gates-of-olympus" } }, { "name": "Floating Dragon", "slug": { "_type": "slug", "current": "floating-dragon" } }, { "name": "Buffalo King Megaways", "slug": { "_type": "slug", "current": "buffalo-king-megaways" } }, { "name": "Fruit Party", "slug": { "_type": "slug", "current": "fruit-party" } } ]
需求为仅查询slug.current等于目标值的对象,目标slug从路由上下文获取,对应变量为params.game。
当前未加筛选的初始代码会返回全量游戏数据,代码如下:
export const getServerSideProps = async ({params}:any) => { const query = `*[_type=="game"]{ name, slug, }`; const games = await sanityClient.fetch(query); return { props: { games, }, }; };
此前尝试直接用模板字符串拼接筛选条件的写法失效,执行后仍返回全量数据,错误写法如下:
*[_type=="game" && slug.current == ${params.game}]
失效原因
直接在GROQ语句中用模板字符串拼接动态值存在两个核心问题:
- 字符串类型的值没有手动包裹引号,会导致查询条件解析异常,筛选逻辑直接不生效
- 直接拼接参数存在查询注入风险,参数中包含特殊字符时会直接破坏查询语法
正确实现
使用Sanity官方推荐的参数化查询方式,动态值通过fetch方法的第二个参数传入,不需要手动拼接字符串,修正后的完整代码如下:
export const getServerSideProps = async ({params}) => { // GROQ语句中用$前缀声明参数,单条查询末尾加[0]直接取匹配结果的第一项 const query = `*[_type=="game" && slug.current == $targetSlug][0]{ name, slug }`; // 传入查询对应的参数,客户端会自动处理类型转义 const game = await sanityClient.fetch(query, { targetSlug: params.game }); // 无匹配数据时返回404状态 if (!game) { return { notFound: true } } return { props: { game, }, }; };
关键说明
- 所有动态查询参数统一通过
$参数名占位,Sanity客户端会自动根据参数类型处理格式,字符串值不需要手动加引号 - 查询条件后加
[0]是因为GROQ的筛选结果默认返回数组,单条文档查询直接取第一个元素即可,无需额外遍历数组取值 - 原查询语句中
slug字段后多余的尾逗号已移除,避免低版本解析器抛出语法错误 - 增加空值判断逻辑,匹配不到对应slug的文档时直接返回404状态,符合Next.js路由处理规范
内容的提问来源于stack exchange,提问作者Sai Krishnadas
相关产品推荐
相关产品推荐

