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

Apollo Client订阅updateQuery不遵循where参数问题求助

解决Apollo Client订阅更新不遵循过滤条件的问题

核心问题分析

你遇到的问题本质是:Apollo Client的订阅更新默认不会自动继承主查询的过滤规则,updateQuery若不手动处理就会混入不符合条件的项;依赖默认缓存更新时,只会修改已有项、无法添加新项——这是因为缓存字段策略未正确关联where参数,导致新项无法匹配到对应的查询缓存条目。

解决方案步骤

1. 优化类型策略的Merge逻辑

offsetLimitPagination的默认实现未严格根据where参数区分缓存条目,需自定义merge函数,确保只有符合当前查询where条件的项才会被合并到缓存中。

修改你的类型策略:

typePolicies: {
  Query: {
    fields: {
      process: {
        keyArgs: ["where", "order_by"], // 明确用这两个参数区分不同缓存条目
        merge(existing, incoming, { args }) {
          if (!existing) return incoming;
          // 过滤incoming中符合当前where条件的项
          const filteredIncoming = incoming.filter(item => {
            // 根据你的where结构实现匹配逻辑,示例为检查deleted状态
            return !item.deleted && matchesWhere(item, args.where);
          });
          // 去重合并:保留existing中未被覆盖的项,加上过滤后的incoming
          const existingIds = new Set(existing.map(p => p.id));
          const merged = [...existing.filter(p => !filteredIncoming.some(i => i.id === p.id)), ...filteredIncoming];
          // 按updated_at排序(按需调整)
          return merged.sort((a, b) => new Date(a.updated_at) - new Date(b.updated_at));
        },
        read(existing = []) {
          return uniqueByRef(existing);
        },
      },
      process_stream: {
        keyArgs: ["where"],
        merge(existing, incoming) {
          // 订阅流仅做去重,主查询的process字段处理过滤逻辑
          if (!existing) return incoming;
          const existingIds = new Set(existing.map(p => p.id));
          return [...existing, ...incoming.filter(i => !existingIds.has(i.id))];
        },
      },
    },
  },
  // 确保单条Process数据的缓存更新正确
  Process: {
    keyFields: ["id"],
  },
}

注:需实现matchesWhere函数,根据你的where参数结构(如_and、_eq等操作符)验证项是否符合条件。

2. 简化订阅的updateQuery

无需在updateQuery中手动过滤,让Apollo利用缓存策略自动处理。调整subscribeToMore,使订阅变量与主查询过滤条件一致:

const { cache } = useApolloClient();

subscribeToMore({
  document: STREAM_PROCESS,
  variables: {
    where: filters.where, // 直接复用主查询的where参数
    cursor: { initial_value: { updated_at: cursor }, ordering: "ASC" },
  },
  updateQuery: (prev, { subscriptionData }) => {
    setCursor(new Date().toISOString());
    if (!subscriptionData.data) return prev;
    
    // 借助缓存的merge逻辑自动处理合并与过滤
    cache.writeQuery({
      query: QUERY_PROCESS,
      variables: { ...filters, limit },
      data: {
        process: [...prev.process, ...subscriptionData.data.process_stream],
      },
    });
    
    return { ...prev };
  },
});

3. 确保服务端订阅返回符合过滤条件的项

优先在服务端调整PROCESS_STREAM的Resolver,确保只返回符合where参数的项——这样客户端无需额外过滤,减少前端逻辑负担。

关键注意点

  • keyArgs必须包含where,让Apollo根据不同过滤条件维护独立缓存条目,避免结果混淆。
  • 自定义merge时务必先过滤incoming项,确保只有符合当前查询条件的内容被合并。
  • 订阅变量需与主查询变量完全一致,保证缓存能匹配到对应条目。

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 06:15:23