FaunaDB - 如何批量更新单个 graphQL 突变中的条目列表?

Posted

技术标签:

【中文标题】FaunaDB - 如何批量更新单个 graphQL 突变中的条目列表?【英文标题】:FaunaDB - How to bulk update list of entries within single graphQL mutation? 【发布时间】:2020-06-29 21:07:47 【问题描述】:

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

当前的 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!]

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

【问题讨论】:

嗨!您能否在答案中分享架构(或架构的一部分)?看起来你可能需要一个 upsert 突变才能这样做,但不幸的是,目前 FaunaDB 上不可用。您可以尝试预先创建城市,然后在根据您共享的突变创建该类型时使用“connect”而不是“create”。 感谢您的建议。我添加了架构细节。 upsert 突变正是我所需要的——“如果不存在插入条目,则更新它们”。如果动物 graphQL 尚不支持它,则可能是 Fauna Query Language。 它绝对可以在 FQL 中作为一个单独的函数来实现。要实现自定义解析器,您可以查看:css-tricks.com/instant-graphql-backend-using-faunadb。我会让 Leo 给你详细信息,因为他是专家。同时,您正在构建的东西似乎很有趣,如果您想与我们讨论或需要帮助以使您的进展顺利,请加入community.fauna.com并与我们交谈 @BrechtDeRooms 我在 FaunaDB 社区问了两次同样的问题,但没有得到任何答复。而且这里似乎也没有回复。此外,文档也没有显示如何使用解析器将参数从 graphql 传递给 UDF 的单个示例。 好的,我没有想到@resolver 文档中缺少架构示例。我已经让我们的文档团队知道并在下面构建了一个答案:) 【参考方案1】:

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

架构

具有参数的架构部分示例:

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')。例如,在我的特定情况下,我们将使用传入的电子邮件通过电子邮件获取帐户,并使用密码传递给 Login 函数,该函数将返回一个秘密(我这样做的原因此处的选择是 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 ReferenceUpdate 函数。 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/ 这可能是好温柔的介绍。

【讨论】:

非常感谢您的回答@BrechtDeRooms。您的示例中唯一缺少的难题是我们需要传入一个 ID 数组才能进行批量更新。那么如何传递所有需要更改的文件呢?例如。 updateBulkArticle(id: [ID]): [Article] @resolver(name: "bulkArticleUpdate" ) 我假设您的意思是带有 id 的 FaunaDB References (Ref) 对吗?如果是这样,我想我明白你的困惑 是的,我可以使用 graphql 在我的应用程序中发送的任何内容,并且 UDF 知道要“批量更新”什么。我相信上面的原始问题具有相同的意图。 是的,我确实忘记解决批量方面的问题。在我编辑答案之前,这是否回答了您的问题:仅传递一组项目的模式示例: type Mutation test(testInput: [String]): [String]! @resolver 调用它:mutation Test test(testInput: ["test"]) 一个示例 UDF,它在其上接收数组映射(或使用 Foreach)并仅返回原始字符串。但是这些元素可以让你用它做一些事情 Query(Lambda(["arr"], Map(Var("arr"), Lambda("x", Var("x"))))) 它必须是 ["arr"],而不是 "arr" 是的,确实可以回答。希望@user1276919 的情况相同,我们可以勾选这个答案。当然 Graphql 不理解“Refs”,但我可以传递一个 ID 数组,然后 UDF 会处理它。非常感谢您的支持。我相信这对未来的其他人也会有用。

以上是关于FaunaDB - 如何批量更新单个 graphQL 突变中的条目列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 FaunaDB 中获取嵌套文档?

我可以在不知道其 ID 的情况下更新 FaunaDB 文档吗?

AWS AppSync 初始批量放置不更新缓存

oracle 如何实现对单个表批量更新

如何使用 Laravel 4.2 在单个查询(不是 for 查询循环)中批量插入或更新

如何从 FaunaDB 的集合中获取所有文档?