Falcor - 未缓存的深层嵌套引用

Falcor - Deep nested references not cached

当我请求包含嵌套引用的路由时,我发现 Falcor 客户端出现问题。

这是一个例子:

考虑以下来自 Falcor 服务器的 JsonGraph 响应 model.get 调用

{
  "todos": {
    "0": { "$type": "ref", "value": ["todosById", "id_0"] },
    "1": { "$type": "ref", "value": ["todosById", "id_1"] },
    "length": 2
  },
  "todosById": {
    "id_0": {
      "name": "get milk",
      "label": { "$type": "ref", "value": ["labelsById", "lbl_0"] },
      "completed": false
    },
    "id_1": {
      "name": "do the laundry",
      "label": { "$type": "ref", "value": ["labelsById", "lbl_1"] },
      "completed": false
    }
  },
  "labelsById": {
    "lbl_0": { "name": "groceries" },
    "lbl_1": { "name": "home" }
  }
}

当我使用以下路径调用 model.get 时,以上所有 jsonGraph 结果应该在缓存中:

model.get(['todos', {from: 0, to: 1}, ['completed', 'label', 'name']])

但是,手动访问缓存,我​​可以看到 todostodosById 在缓存中,但 labelsById 没有。

我不确定,但看起来 labelsById 不在缓存中,因为它是二级引用?

我是不是遗漏了什么,或者这是 Falcor 缓存的预期行为? 有没有办法强制 labelsById 进入缓存,这样就不会发出额外的数据源请求?

感谢任何帮助!

问题可以在这个小项目中重现: https://github.com/ardeois/falcor-nested-references-cache-issue

更新

感谢@james-conkling 的回答 json 图可以通过执行以下操作来缓存 model.get:

model.get(
  ['todos', {from: 0, to: 1}, ['completed', 'name']],
  ['todos', {from: 0, to: 1}, 'label', 'name']
);

然而,在服务器端 Falcor Router 会调用 todos[{integers:indices}] 路由两次。这可能会影响 API 或对 Falcor 服务器前端的任何数据库调用。

在路径集 ['todos', {from: 0, to: 1}, ['completed', 'label', 'name']] 中,以 completedname 键结尾的路径在一个原子处终止。但是以 label 键结尾的路径在 ref 处终止。如果你想真正遵循该参考,你必须将它作为第二条路径包括在内:

[
   ['todos', {from: 0, to: 1}, ['completed', 'name']],
   ['todos', {from: 0, to: 1}, 'label', 'name']
]

一般而言,所有路径都应终止于原子,绝不能终止于引用。我不确定终止于 ref 的路径的预期行为是什么,或者即使它定义明确(如 所述,行为已从 v0 更改为 v1)。

model.get(...paths) 调用可以采用多个 pathSet 数组,因此重写查询应该像

一样简单
model.get(
  ['todos', {from: 0, to: 1}, ['completed', 'name']],
  ['todos', {from: 0, to: 1}, 'label', 'name']
);

编辑

如以下评论所述,由于路由器处理程序一次只能解析一个路径集,因此具有多个路径集的 GET 请求可能会导致对上游支持的多个请求 service/db。一些可能的解决方案:

使用单一路径

使用单个路径重写请求 ['todos', range, ['completed', 'name', 'label'], 'name']。从技术上讲,除了 todos.n.label.name(确实存在)之外,此请求还要求 todos.n.completed.nametodos.n.label.name(不存在)。

但是,如果您的路由器处理程序 returns pathValues 的路径比匹配路径短,则应将较短的 pathValues 合并到您的 jsonGraph 缓存中。例如。当匹配 todos.0.completed.name, return { path: ['todos', 0, 'completed'], value: true }, 而当匹配 todos.0.label.name return { path: ['todos', 0, 'label', 'name'], value: 'First TODO' }.

这可能是最简单的方法,但这意味着您的查询在语义上并不是真正正确的(您是在故意询问不存在的路径)。

路由器发出的批量上行请求

在您的路由器中,将上游请求批处理到您的支持 service/db。这并不总是直截了当的。一种可能的方法是使用 facebook 的 data-loader, written to solve an equivalent problem w/ GraphQL routers, but not necessarily tied to GraphQL. Another approach could use a custom reducer function to combine requests issued w/i the same tick (e.g. here).

重写您的架构

这样所有需要同时请求的路径都是一样长的。不过,这并不总是可能的,所以 :shrug.