2

我想批量更新动物数据库中带有 graphQL 突变的条目列表。输入数据是来自外部来源的冠状病毒病例列表。它会经常更新。如果条目名称存在于 collectionio 中,则突变应更新现有条目,如果不存在则创建新条目。

当前的 GRAPHQL 突变

mutation UpdateList($data: ListInput!) {
  updateList(id: "260351229231628818", data: $data) {
    title
    cities {
      data {
        name
        infected
      }
    }
  }
}

图形变量

{
  "data": {
    "title": "COVID-19",
    "cities": {
      "create": [
        {
          "id": 22,
          "name": "Warsaw",
          "location": {
            "create": {
              "lat": 52.229832,
              "lng": 21.011689
            }
          },
          "deaths": 0,
          "cured": 0,
          "infected": 37,
          "type": "ACTIVE",
          "created_timestamp": 1583671445,
          "last_modified_timestamp": 1584389018
        }
      ]
    }
  }
}

架构

type cityEntry {
  id: Int!
  name: String!
  deaths: Int!
  cured: Int!
  infected: Int!
  type: String!
  created_timestamp: Int!
  last_modified_timestamp: Int!
  location: LatLng!
  list: List
}

type LatLng {
  lat: Float!
  lng: Float!
}

type List {
  title: String!
  cities: [cityEntry] @relation
}

type Query {
  items: [cityEntry!]
  allCities: [cityEntry!]
  cityEntriesByDeathFlag(deaths: Int!): [cityEntry!]
  cityEntriesByCuredFlag(cured: Int!): [cityEntry!]
  allLists: [List!]
}

每次突变运行时,它都会创建新的副本。在单个突变中更新列表的最佳方法是什么?

4

1 回答 1

6

我为延迟道歉,我不确定丢失的信息到底是什么,因此我首先发表评论:)。

架构

具有参数的模式部分示例:

type Mutation {
  register(email: String!, password: String!): Account! @resolver
  login(email: String!, password: String!): String! @resolver
}

当在 FaunaDB 中导入这样的模式时,将提供占位符函数。

UDF 参数

函数存根

如您所见,该函数所做的所有事情都是 Abort 并显示该函数仍需实现的消息。实现从一个带有参数的 Lambda 开始,这些参数必须与您在解析器中定义的内容相匹配。

Query(Lambda(['email', 'password'],
    ... function body ...
))

使用参数是通过 Var 完成的,在这种情况下,这意味着 Var('email') 或 Var('password')。例如,在我的特定情况下,我们将使用传入的电子邮件通过电子邮件获取帐户,并使用密码传递给登录函数,该函数将返回一个秘密(我在这里选择的原因是返回GraphQL 解析器的值必须是有效的 GraphQL 结果(例如纯 JSON

Query(Lambda(['email', 'password'],
    Select(
      ['secret'],
      Login(Match(Index('accountsByEmail'), Var('email')), {
        password: Var('password')
      })
    )
))

通过 GraphQL 调用 UDF 解析器

最后,调用的时候怎么传参数呢?从 GraphQL 操场上应该很清楚,因为它将为您提供文档和自动完成功能。例如,这是在我的模式导入后自动生成的 GraphQL 文档告诉我的:

在此处输入图像描述

这意味着我们可以这样称呼它:

mutation CallLogin {
  login (
    email: "<some email>"
    password: "<some pword>"
  )
}

批量更新

对于批量更新,您还可以将值列表传递给用户定义函数 (UDF)。假设我们希望通过 UI 将特定团队中的多个帐户组合在一起,因此希望同时更新多个帐户。

我们的 Schema 中的突变可能如下所示(GraphQL 中的 ID 类似于字符串)

type Mutation { updateAccounts(accountRefs: [ID]): [ID]! @resolver } 

然后,我们可以通过提供从 FaunaDB 收到的 id 来调用突变(如果您混合 FQL 和 GraphQL,则不是字符串,而不是 Ref,如果您只使用 GraphQL,请不要担心)。

mutation {
    updateAccounts(accountRefs: ["265317328423485952", "265317336075993600"] )
}

就像以前一样,我们必须填写由 FaunaDB 生成的用户定义函数。只接收数组并返回它的骨架函数如下所示:

Query(Lambda(['arr'], 
  Var('arr')
))

有些人可能已经看到了更简单的语法,并且很想使用它:

Query(Lambda(arr => arr))

但是,目前在传入数组时这不适用于 GraphQL,这是一个将修复的已知问题。下一步是实际循环数组。FQL 不是声明性的,它从函数式语言中汲取灵感,这意味着您只需使用“map”或“foreach”就可以做到这一点

Query(Lambda(["accountArray"], 
  Map(Var("accountArray"), 
      Lambda("account", Var("account")))
))

我们现在遍历列表,但还没有对它做任何事情,因为我们只是在地图的主体中返回帐户。我们现在将更新帐户并在其中设置一个值“teamName”。为此,我们需要采用 FaunaDB Reference的Update函数。GraphQL 向我们发送字符串而不是引用,因此我们需要将这些 ID 字符串转换为带有Ref的引用,如下所示:

 Ref(Collection('Account'), Var("account"))

如果我们把它们放在一起,我们可以在账户 ID 列表中添加一个额外的属性,如下所示:

Query(Lambda(["accountArray"], 
  Map(Var("accountArray"), 
    Lambda("account", 
       Do(
         Update(
          Ref(Collection('Account'), Var("account")),
          { data: { teamName: "Awesome live-coders" } }
        ),
        Var("account")
      )
    )
  )
))

在 Map 的末尾,我们只需使用 Var("account") 再次返回帐户的 ID,以便返回纯 JSON 的内容,否则我们将返回不仅仅是 JSON 且不会返回的 FaunaDB Refs被 GraphQL 调用接受。

在此处输入图像描述

传递更复杂的类型。

有时你想传入更复杂的类型。假设我们有一个简单的 todo 模式。

type Todo {
  title: String!
  completed: Boolean!
}

我们希望将具有特定标题的待办事项列表的完成值设置为 true。我们可以在 FaunaDB 生成的扩展模式中看到有一个 TodoInput。

在此处输入图像描述

如果您看到该扩展模式,您可能会想:“嘿,这正是我需要的!” 但是当你写你的突变时你不能访问它,因为你在创建时没有架构的那部分,因此不能只写:

type Mutation { updateTodos(todos: [TodoInput]): Boolean! @resolver } 

因为它将返回以下错误。 在此处输入图像描述

但是,我们可以自己将其添加到模式中。Fauna 只会接受您已经编写过它而不是覆盖它(确保您保留必填字段,否则您生成的“createTodo”突变将不再起作用)。

type Todo {
  title: String!
  completed: Boolean!
}

input TodoInput {
  title: String!
  completed: Boolean!
}

type Mutation { updateTodos(todos: [TodoInput]): Boolean! @resolver } 

这意味着我现在可以写:

mutation {
  updateTodos(todos: [{title: "test", completed: true}])
}

并深入研究 FQL 函数来处理这个输入。或者,如果您想在数据中包含 ID,您可以定义一个新类型。

input TodoUpdateInput {
  id: ID!
  title: String!
  completed: Boolean!
}
type Mutation { updateTodos(todos: [TodoUpdateInput]): Boolean! @resolver } 

一旦你掌握了它并想了解更多关于 FQL 的信息(这是一个完全不同的主题),我们目前正在编写一系列文章以及第一篇出现在这里的代码:https ://css-tricks.com/ rethinking-twitter-as-a-serverless-app/这可能是一个很好的温和介绍。

于 2020-05-10T12:38:03.253 回答