AWS 的嵌套 GraphQL 突变 Amplify/AppSync

Nested GraphQL mutations with AWS Amplify/AppSync

我已经访问了 AWS 论坛,但我希望在这里得到更广泛受众的关注。我正在寻找有关以下 question.

的任何指导

我会post下面的问题:

您好,非常感谢您的帮助。

我是 Amplify/GraphQL 的新手,正在努力让突变发挥作用。具体来说,当我向模型添加连接时,它们永远不会出现在模拟 api 生成器中。如果我把它们写出来,他们会说“输入不存在”。我四处搜索,人们似乎说“在主要项目之前创建子项目,然后更新主要项目”,但我不希望那样。我有一个大型表单,其中包含多个多对多关系,它们都需要有效才能保存主表单。我不知道如何创建每个子项,然后再创建主项。

但是,这些项目列在响应的可用数据中。在下面的示例中,输入中缺少地址、股东、董事会成员。

None 个带有“@connection”的字段出现在创建 api 中作为输入。 help/guidance 我会拿走任何我能得到的。我似乎没有理解这里的核心内容。

这是我的模型:

type Company @model(queries: { get: "getEntity", list: "listEntities" }, subscriptions: null) {
id: ID!
name: String!
president: String
vicePresident: String
secretary: String
treasurer: String
shareholders: Shareholder @connection
boardOfDirectors: BoardMember @connection
addresses: [Address]! @connection
...
}

type Address @model{
id: ID!
line1: String!
line2: String
city: String!
postalCode: String!
state: State!
type: AddressType!
}

type BoardMember @model{
id: ID!
firstName: String!
lastName: String!
email: String!
}

type Shareholder @model {
id: ID!
firstName: String!
lastName: String!
numberOfShares: String!
user: User!
}

----一天后----

我已经取得了一些进步,但仍然对发生的事情缺乏一些了解。

我已将架构更新为:

type Company @model(queries: { get: "getEntity", list: "listEntities" }, subscriptions: null) {
id: ID!
name: String!
president: String
vicePresident: String
secretary: String
treasurer: String
...
address: Address @connection
...
}

type Address @model{
id: ID!
line1: String!
line2: String
city: String!
postalCode: String!
state: State!
type: AddressType!
}

我删除了我尝试的多对多关系,现在我仅限于一家只有 1 个地址的公司。我想这是一个未来的问题。但是,现在在输入列表中,'CompanyAddressId' 位于输入列表中。这表明它希望我在公司之前保存地址。地址只是公司的一部分,如果地址无效并且表单的其他部分失败并且用户退出,我不想保存地址。

我不明白为什么我不能一次写出所有字段?按照上面的模式,我还会有股东、董事会成员等。所以我必须先创建董事会成员和股东名单,然后才能创建公司?这似乎倒退了。

再一次,任何帮助我弄清楚我遗漏了什么的尝试都将不胜感激。

谢谢

--编辑-- 我在资源管理器中看到的

-- 编辑 2-- 这是基于您的示例的新生成的操作。您会看到 Company 现在获取一个地址 Id——我们之前讨论过。但这与股东无关。为了写出股东,我必须使用需要公司 ID 的 'createShareholder',但公司尚未创建。彻底糊涂了。

@engam 我希望你能帮助解决新问题。非常感谢!

以下是您可以尝试的一些概念:

对于@model 指令,请在不重命名查询的情况下进行尝试。 AWS Amplify 为自动生成的查询命名。例如,要获取公司,它将是 getCompany,对于列表,它将是 listCompanys。如果你还想给它起新的名字,你可以稍后再更改。

对于@connection 指令: 需要在连接的两个 table 上设置 @connection。此外,如果您想要多对多连接,则需要添加第三个 table 来处理连接。当您的架构中有许多连接时,为连接命名也很有用。

只有您在架构中创建的标量类型、标准 schalars(如 String、Int、Float 和 Boolean)以及 AWS 特定的 schalars(如 AWSDateTime)才能用作架构中的 schalars。看看这个 link: https://docs.aws.amazon.com/appsync/latest/devguide/scalars.html

这是我认为您想要实现的一些示例:

type Company @model {
   id: ID!
   name: String
   president: String
   vicePresident: String
   secretary: String
   treasurer: String
   shareholders: [Shareholder] @connection(name: "CompanySharholderConnection")
   address: Address @connection(name: "CompanyAdressConnection") #one to many example
   # you may add more connections/attributes ...
}

# table handling many-to-many connections between users and companies, called Shareholder.
type Shareholder @model {
   id: ID!
   company: Company @connection(name: "CompanySharholderConnection")
   user: User @connection(name: "UserShareholderConnection")
   numberOfShares: Int #or String
}

type User @model {
   id: ID!
   firstname: String
   lastname: String
   company: [Shareholder] @connection(name: "UserShareholderConnection")
   #... add more attributes / connections here
}

# address table, one address may have many companies
type Address @model {
  id: ID!
  street: String
  city: String
  code: String
  country: String
  companies: [Company] @connection(name: "CompanyAdressConnection") #many-to-one connection
}

每个这种类型...@model 都会生成一个新的 dynamoDB table。此示例将使您可以创建多个公司和多个用户。要将用户添加为公司的股东,您只需要在Shareholder table中创建一个新项目,方法是创建一个新项目,ID为用户table,ID为公司里的公司table+加多少股。

编辑

请注意,当您在两个 table 之间生成连接时,amplify cli(使用 cloudformation 进行后端更改)将为一个或多个 dynamodb tables,让appsync可以高效的给你数据。

dynamodb 中的限制,使得当您编辑 table 时一次只能生成一个索引 (@connection)。我认为您可以在创建新的 table (@model) 时一次做更多的事情。因此,当您编辑一个或多个 table 时,在每次放大推送/放大发布之间,一次只能删除或添加一个连接。否则,当您推送更改时,cloudformation 将失败。清理起来可能一团糟。因此,我不得不多次删除整个环境,幸好不是在生产环境中。

更新

(我还使用 som 值更新了架构中的地址 table); 要在创建新公司时连接新地址,您首先必须在 dynamoDb 的地址 table 中创建一个新地址项。

从 appsync 生成的这个变化可能被命名为 createAddress() 并接受一个 createAddressInput。

创建地址后,您将收到整个新创建的项目,包括自动创建的 ID(如果您没有自己添加)。

现在您可以保存正在创建的新公司。 createCompany 突变采用的属性之一是您创建的地址的 ID,可能命名为 companyAddressId。在此处存储地址 ID。当您随后使用 getCompany 或 listCompanys 检索您的公司时,您将获得您公司的地址。

Javascript 示例:

const createCompany = async (address, company) => {
   // api is name of the service with the mutations and queries
   try {
      const newaddress = await this.api.createAddress({street: address.street, city: address.city, country: address.country});
      const newcompany = await this.api.createCompany({
        name: company.name,
        president: company.president,
        ...
        companyAddressId: newaddress.id
      })
   } catch(error) {
      throw error
   }
   
  
}

// and to retrieve the company including the address, you have to update your graphql statement for your query:

const statement = `query ListCompanys($filter: ModelPartiFilterInput, $limit: Int, $nextToken: String) {
   listCompanys(filter: $filter, limit: $limit, nextToken: $nextToken) {
      __typename
      id
      name
      president
      ...
      address {
         __typename
         id
         street
         city
         code
         country
      }
   }

}

`

AppSync 现在将检索您的所有公司(取决于您的过滤器和限制)以及您已将地址连接到的那些公司的地址。

编辑 2 带有@model 的每种类型都是对aws 中dynamoDb table 的引用。因此,当您在两个 table 之间创建一对多关系时,当两个项目都是新的时,您首先必须在一对多关系中创建 'many'。在dynamoDb Company tables中,一个地址可以有很多公司,而一个公司只能有一个地址,你必须存储公司地址的id(dynamoDB主键)。您当然可以在前端生成地址 ID,并将其用于地址 ID,并将其用于公司的 addressCompanyId 并使用 await Promise.all([createAddress(...),createCompany(...)) 但是如果一个失败,将创建另一个(但是通常 appsync api 是非常 stable,所以如果你发送的数据是正确的,它不会失败。

另一个解决方案,如果您通常不需要 create/update 多个 table 中的多个项目,您可以将地址直接存储在公司项目中。

type Company @model {
  name: String
  ...
  address: Address # or [Address] if you want more than one Address on the company
}
type Address {
   street: String
   postcode: String
   city: string
}

那么地址类型将是 dynamoDb 中相同 table 中相同项目的一部分。但是您将失去对地址(或股东)进行查询以查找地址并查看哪些公司位于那里的能力(或者类似地查找一个人并查看该人拥有哪些公司的股份)。通常我不喜欢这种方法,因为它会将您的应用程序锁定在一个特定的事物上,并且以后很难创建新功能。

据我所知,不可能在一个 graphql (Amplify/AppSync) 突变中在多个 dynamoDb tables 中创建多个项目。因此,使用 Promise.all() 异步等待并在创建项目之前手动生成 id 属性前端可能是您的最佳选择。