mongoose 使用MongoDB高效解析嵌套GraphQL查询的最佳方法

ekqde3dh  于 11个月前  发布在  Go
关注(0)|答案(1)|浏览(115)

我试图写一个解析器,它获取属于客户的帐户。parent.accounts属性是一个account_id s数组。在下面的代码中,我试图为每个客户获取一个帐户数组。

import Account from "../models/accounts.js";
import Customer from "../models/customers.js";
import { AccountInterface } from "../types/accounts.js";
import { CustomerInterface } from "../types/customers.js";

const resolvers = {
    Query: {
        // some other code
        customers: async () => await Customer.find(),
    },
    Customer: {
        accounts: async (parent: CustomerInterface) => {
            const response = await Account.find()
                .where("account_id")
                .in(parent.accounts);
            return response;
        },
    },
};
export default resolvers;

字符串
代码运行并返回预期的输出。问题是它太慢了,因为解析器在parents.accounts数组中查询数据库中的每个元素,并且当从数据库执行“get all”请求时,它变得越来越慢。
有没有更好的方法来编写嵌套查询的解析器?如果有,如何编写?

zmeyuzjn

zmeyuzjn1#

问题:

这对我来说似乎是一个扩展问题。这可能发生在任何技术中,你试图一次加载这么多数据而没有限制。如果你允许用户找到客户,然后在不增加任何限制/最大复杂性的情况下找到帐户,用户可能会从你的服务器请求大量数据,并且它可能必须查询比它返回的更多的数据,正如您所注意到的,其中一个问题可能是性能,另一个问题是网络带宽,这可能会花费您更多的时间。
假设你估计有10,000个客户,每个客户有3个帐户。那么你的帐户表中有10,000 * 3 = 30,000个帐户。这使得你的get all查询搜索超过10,000个客户,然后对于这10,000个客户中的每个客户它将搜索超过30个,000个帐户(除非你在你的字段上建立索引,否则它可能会好得多,在索引解决方案中有更多关于这一点的信息)。这意味着你刚刚搜索了超过10,000 * 30,000 =300,000,000个扫描条目,你最终会返回30个,如果这两个数字中的任何一个大到任何数量级(也就是说,如果您在帐户或客户的末尾添加一个或多个0),问题就会变得更糟。
如果你可以限制客户数量为100在同一时间你只会搜索超过100客户 * 30,000帐户=3,000,000扫描项目总这是更好的(同样,扫描的帐户数量取决于您是否索引字段,因此,在实际中,使用索引时,这个数字更像是100或1000个扫描项目。)它也只会返回100个客户 * 每个客户3个帐户=300个帐户

解决方案

有几个不同的解决方案,我会建议什么会帮助你。

查询限制

人们通常会选择两种解决方案来限制查询而不会出错/失败,选择哪一种取决于你的用例。在这种情况下,你可能会希望限制从数据库返回的任何集合/列表的数量,在你当前的情况下,包括帐户和用户。
1.使用mongoose使用skip & limit分页。这比另一种方法简单得多,尽管没有那么健壮。
1.使用游标分页。实现中继连接可能是最好的选择,因为这是实现游标分页的最标准方法,即使你不使用react-在你的前端上的中继。为了帮助你理解用光标分页和中继的一节,关于它如何期望在服务器上完成连接。relay connections specification是学习实现中继连接的好方法。最后,如果你如果你不想自己实现它,你可以看看我写的my own mongoose library which implements relay connections,它是MIT授权的,或者只是看看它来获得一些想法。

增加最大查询复杂度

我还建议在查询限制之上,当你的graphql模式达到最大查询复杂度时,你会出错。一旦你有了限制,你的graphql框架中可能会有帮助库来帮助你做到这一点。这些库会接受你的查询,甚至在它运行之前决定它是否满足最大复杂度要求。这样做的目的不是限制返回的内容,但是如果客户端试图请求太多数据,则会提前出错(例如,考虑拒绝服务攻击,其中客户端可能是坏的参与者)。

索引您的收藏

这可以大大提高你的搜索速度。想想看,它将把O(n)的搜索时间减少到O(log n)的搜索时间。这是对非索引查询的巨大改进。所以,如果其他两个问题不足以修复查询时间,这可能是一个非常重要的选择。您通常只在您正在搜索其值的任何字段上使用索引。例如您的帐户的account_id这是你想要的地方。

相关问题