如何让 GraphQL 在不进行轮询的情况下从数据库中获取实时/新数据?
Posted
技术标签:
【中文标题】如何让 GraphQL 在不进行轮询的情况下从数据库中获取实时/新数据?【英文标题】:How do I get GraphQL to get live/new data from database without polling? 【发布时间】:2021-07-19 02:27:44 【问题描述】:我有一个运行 GraphQL、MongoDB + Mongoose 和 Apollo 的后端。此应用程序具有用户帐户和朋友列表的功能。每个用户都可以登录他们的帐户并查看具有当前“状态”的朋友列表;如果朋友更改了他们的状态,我需要将该更改反映在用户方面。这方面的一个例子是 Facebook 的 Messenger 上的“绿点”,它会告诉您您的一位朋友何时在线使用该应用程序。
我一直在搜索 GraphQL 的文档,并且有人建议我订阅或实时查询。据我了解,订阅似乎是大多数建议,实时查询不是 GraphQL 的正式组成部分或已被删除。
有没有人有解决方案来使用 GraphQL/MongoDB 获取“实时”数据,而不涉及针对这种情况的轮询?
【问题讨论】:
您在问题中提到的订阅模式可能是要走的路。您是否有不想使用订阅的具体原因?我不知道针对您想要使用 GraphQL 做什么而量身定制的不同解决方案。或者,您可以使用裸骨 websockets,但如果您要使用该方法,则必须自己实现 GraphQL。 遵循一些教程,运行一些准备好的/分叉的 repo 示例 @YvesGurcan 不,我对使用订阅没有任何问题。我刚刚看到一些关于实时查询的东西,它看起来更像我正在寻找的东西,但我找不到任何好的文档,并认为它已被弃用或从未退出测试版。 更多的是关于可能的扩展问题 - github.com/hasura/graphql-engine/blob/master/architecture/… 【参考方案1】:您似乎已经有了答案:subscriptions!
使用您的示例,考虑两个用户 - mikep17 和 mcy。您是 mikep17,登录到您的应用程序并查看您的朋友列表及其状态。我是您的朋友,我在您查看此列表时登录,并且您希望在应用程序的 UI 中看到它。
在前端,在您的应用程序实例中,您的应用程序将执行对某个事件的订阅。我们称之为friendStatusChange
。现在您的应用程序正在“侦听”该事件以便做出相应的响应。假设当您的应用程序接收到事件时,它可以解析出“我”(mcy)从offline
=> online
更改的信息,然后使用它在我的用户名旁边添加“绿点”。
在后端,您的 GraphQL 服务器将具有处理您的用户功能的代码 - 登录、注销等。需要对其进行增强以挂钩这些操作并在适用时“发布”friendStatusChange
事件。
现在,您的客户端不再不断询问(轮询)“朋友的状态是否发生了变化?现在怎么样?现在?”,它可以只听并等待您的服务器轻拍它的肩膀并说“嘿,伙计,你的朋友mcy
的状态改变了”。
【讨论】:
嗨,mcy,谢谢,是的,我想我会尝试订阅。我想我的困惑是订阅如何知道数据库中的数据已更改。我见过其他使用 websockets 的选项,但在所有教程中,它们都没有连接到数据库,而是在内存中运行。我将尝试将 changeStatus 突变设置为发布者/订阅者,并将“我的朋友”数组设置为订阅者,看看这是否有效。 知道何时发布事件的方法是挂钩导致数据库更改的突变代码。您有处理用户登录时的代码,对吗? (突变)因此,在突变代码中,您为带有参数(例如,userId
)的事件(例如,changeStatus
)添加发布,并且客户端注册监听事件的订阅。
嘿再次@mcy,我只是想跟进,对于将来搜索此内容的任何人:我使用了查询和订阅,并将这两件事与阿波罗中的SubscribeToMore
结合在一起- React 前端,并将新的 Subscription 数据与原始 Query 数据合并。在后端,有一个附加到订阅的withFilter
函数,让我可以检查return payload.recieverID === context.recieverID;
之类的内容,以确保将数据发送给正确的“用户”。我找到的示例:howtographql.com/react-apollo/8-subscriptions以上是关于如何让 GraphQL 在不进行轮询的情况下从数据库中获取实时/新数据?的主要内容,如果未能解决你的问题,请参考以下文章
GraphQL 是不是适合在不进行多次查询的情况下从后端检索多级 facet 数据?
Haskell:在不轮询的情况下监控文件(在 linux 中使用 inotify)
PHP & MySQL:检查表的数据是不是在没有轮询的情况下发生了变化?
如何干净的实现Android/Java Socket 长连接通信