如何在EdgeDB TypeScript客户端的e.for循环中条件插入可选链接?
EdgeDB批量插入时处理可选关联字段的问题
问题背景
我正在使用EdgeDB TypeScript客户端,Schema简化如下:
type Ratings { property imdb -> float32; } type Movie { required property year -> int16; single link ratings -> Ratings { constraint exclusive; } }
Movie.ratings是可选字段,可为null。我想用e.for批量插入电影,示例调用:
insertMovies([ // 无评分的电影 { year: 1900, ratings: null, }, // 带评分的电影 { year: 1900, ratings: { imdb: 9 }, }, ]);
当前实现抛出错误:QueryError: INSERT statements cannot be used inside conditional expressions,代码如下:
export async function insertMovies(movies: MovieNoId[]) { const query = e.params({ items: e.json }, params => { return e.for(e.json_array_unpack(params.items), item => { return e .insert(e.Movie, { year: e.cast(e.int16, item.year), genresIds: e.cast(e.array(e.int32), item.genresIds), ratings: e.op( e.insert(e.Ratings, { imdb: e.cast(e.float32, item.ratings.imdb), metacritic: e.cast(e.float32, item.ratings.metacritic), rottenTomatoes: e.cast(e.float32, item.ratings.rottenTomatoes), }), "if", e.op("exists", item.ratings), "else", e.cast(e.Ratings.__element__, e.set()) // 设置为null ), }) .unlessConflict(); }); }); return query.run(edgedbClient, { items: movies }); }
我期望的逻辑是:
... ratings: item.ratings ? e.insert(e.Ratings, { imdb: e.cast(e.float32, item.ratings.imdb), }) : null, ...
但写法无效,请问如何在e.for循环中仅当ratings存在时才插入对应的Ratings对象?
解决方案
EdgeDB不允许在普通条件表达式(如三元运算符、e.op("if"))的分支中直接嵌套INSERT语句,这是触发错误的核心原因。要实现需求,需改用EdgeQL原生的e.if函数来构建合法的查询结构:
export async function insertMovies(movies: MovieNoId[]) { const query = e.params({ items: e.json }, params => { return e.for(e.json_array_unpack(params.items), item => { // 检查ratings是否存在且非null const hasRatings = e.op(item.ratings, "is not", null); // 用e.if处理条件分支,兼容INSERT操作 const ratingsValue = e.if( hasRatings, // 存在ratings时插入对应记录 e.insert(e.Ratings, { imdb: e.cast(e.float32, item.ratings.imdb), metacritic: e.cast(e.float32, item.ratings.metacritic), rottenTomatoes: e.cast(e.float32, item.ratings.rottenTomatoes), }), // 不存在时返回null,确保类型匹配 e.cast(e.optional(e.Ratings.__element__), null) ); return e .insert(e.Movie, { year: e.cast(e.int16, item.year), genresIds: e.cast(e.array(e.int32), item.genresIds), ratings: ratingsValue, }) .unlessConflict(); }); }); return query.run(edgedbClient, { items: movies }); }
关键说明
- 条件判断:用
e.op(item.ratings, "is not", null)精准检测ratings的存在性,避免JSON解析带来的歧义。 - 合法条件构造:
e.if是EdgeDB支持的原生条件函数,允许在分支中包含INSERT操作,符合查询语法规则。 - 类型兼容:通过
e.cast(e.optional(e.Ratings.__element__), null)确保返回值与Movie.ratings的可选类型匹配,避免类型错误。
修改后即可实现批量插入逻辑:仅当电影包含ratings数据时创建对应的Ratings记录,否则将ratings字段设为null。
内容的提问来源于stack exchange,提问作者httpete
相关产品推荐
相关产品推荐

