You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 16:35:21