Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
GraphQL:你能改变查询的结果吗?_Graphql - Fatal编程技术网

GraphQL:你能改变查询的结果吗?

GraphQL:你能改变查询的结果吗?,graphql,Graphql,在写这篇文章时,我意识到我想在GraphQL中做一些非常具体的事情,但我看不到实现它的好方法。这个想法是: GraphQL的一个优点是它允许您进行灵活的查询。例如,如果我想在特定的论坛中查找每个用户的所有帖子上的所有评论,那么我可以进行查询 query{ findForum(id:7){ users{ posts{ comments{ content } } } } } 这很好。通常,您希望收

在写这篇文章时,我意识到我想在GraphQL中做一些非常具体的事情,但我看不到实现它的好方法。这个想法是:

GraphQL的一个优点是它允许您进行灵活的查询。例如,如果我想在特定的
论坛
中查找每个
用户的所有
帖子
上的所有
评论
,那么我可以进行查询

query{
  findForum(id:7){
    users{
      posts{
        comments{
          content
        }
      }
    }
  }
} 
这很好。通常,您希望收集数据,目的是对其进行变异。因此,在本例中,可能我不想获取所有这些注释,而是想删除它们。一个简单的建议是在
comment
类型上实现一个
deletecoment
字段,该字段会改变调用它的对象。这是错误的,因为请求被标记为查询,所以它不应该改变数据

因为我们正在变异数据,所以我们肯定应该将其标记为
变异
。但是我们失去了进行我们想要的查询的能力,因为
findForum
是一个查询字段,而不是一个变异字段。解决这个问题的一种方法可能是重新定义突变类型中所需的所有查询字段。这显然不是一个好主意,因为您重复了大量代码,并且还使
查询
的功能成为
变异
功能的严格子集

现在,我所认为的“传统”解决方案是制作一个突变域,它完成这项工作,而不是其他任何事情。因此,您定义了一个变异字段
deleteAllUserPostCommentsByForum
,它接受一个参数,并以明显的方式实现它。但现在你已经失去了灵活性!如果您决定显式地查找
用户
,并删除他们的所有帖子,或者如果您只想删除他们的一些帖子,则需要一个全新的变异字段。与REST相比,我认为GraphQL在这方面非常有用


那么,有没有一个好方法可以同时避免这些问题呢

在幕后,查询和突变之间唯一真正的区别在于,如果一个操作包含多个突变,那么它们将按顺序(一次一个)解析,而不是同时解析。同时解析查询和所有其他字段。这意味着对于这样的操作:

mutation myOperation {
  editComment(id: 1, body: "Hello!")
  deleteComment(id: 1)
}
mutation myOperation {
  deleteComment(id: 1) {
    id
    name
  }
}
type Mutation {
  createOrUpdateComment(comment: CommentInput)
}

input CommentInput {
  id: ID
  userId: ID
  body: String
}
editComment
变异将在
deleteComment
变异之前解决。如果这些操作是查询,它们将同时运行。同样,考虑如果你有一个突变,返回一个对象,像这样:

mutation myOperation {
  editComment(id: 1, body: "Hello!")
  deleteComment(id: 1)
}
mutation myOperation {
  deleteComment(id: 1) {
    id
    name
  }
}
type Mutation {
  createOrUpdateComment(comment: CommentInput)
}

input CommentInput {
  id: ID
  userId: ID
  body: String
}
在这种情况下,
id
name
字段也会同时解析(因为,即使它们作为突变的一部分返回,字段本身也不是突变)

查询和突变之间的这种行为差异凸显了为什么按照惯例,我们为每个操作定义一个突变,并避免像您的问题所建议的那样“嵌套”突变

使突变更灵活的关键在于如何将输入传递给突变,然后如何在解析器中处理这些输入。与其进行
deleteAllUserPostCommentsByForum
变异,不如进行
DeleteCommentsByForum
变异,以接受更稳健的输入类型,例如:

input DeleteCommentsInput {
  forumId: ID
  userId: ID
}
然后,您的解析器只需要处理可能传入的输入字段的任何组合。如果您使用的是db,这种输入很容易转换为
WHERE
子句。如果您意识到您需要额外的功能,例如在某个日期之前或之后删除注释,那么您可以将这些字段添加到您的输入类型中,并相应地修改您的解析器——无需创建新的变体

实际上,您可以以类似的方式处理创建和编辑,并使内容保持干燥。例如,您的模式可能如下所示:

mutation myOperation {
  editComment(id: 1, body: "Hello!")
  deleteComment(id: 1)
}
mutation myOperation {
  deleteComment(id: 1) {
    id
    name
  }
}
type Mutation {
  createOrUpdateComment(comment: CommentInput)
}

input CommentInput {
  id: ID
  userId: ID
  body: String
}

然后,您的冲突解决程序可以检查是否包含ID——如果包含ID,则将该操作视为更新,否则将该操作视为插入。当然,在这种情况下使用非Null可能会变得棘手(
userId
可能需要创建,但不需要更新),因此,对于每种操作,都需要单独的输入类型。然而,希望这仍然说明了如何利用输入类型使突变更加灵活。

我想你会失去许多间接方面

尝试创建“灵活”查询可能会导致服务器操作高度未优化

查询是按结构逐级解析的,这可能会导致处理许多不必要的数据(内存使用率高)。它不能在较低的层(如sql server)上进行优化-它将导致一个幼稚的实现(处理),就像许多“手动触发”的sql查询,而不是一个更复杂的带条件的查询

在这种情况下,f.e.服务器根本不需要所有用户,而用户的帖子/评论通常包含
user\u id
(以及论坛/线程/帖子id)字段-可以直接在一个表上处理(使用连接的帖子)。您不需要整个结构只影响某些元素

将graphQL的真正威力和灵活性放在解析器上。


请注意,删除所有注释或仅删除某些注释可能会完全不同。解析器可以选择更好的方式(通过Daniel所写的参数),但为了简单(API的可读性),最好有一个单独的变体。

这是一个有趣的响应,但我认为它与我所寻找的有点不一致。您提出的想法(使用输入类型指定要修改的内容)是好的。我想我想说的是,有时候“做一个查询”然后“改变结果”感觉更自然——当然,这是我在服务器端做的。由于GQL在进行查询方面非常强大,所以它有点