在使用筛选器参数和order by时,如何在GraphQL/Relay中使用(不透明)游标
设想以下GraphQL请求:在使用筛选器参数和order by时,如何在GraphQL/Relay中使用(不透明)游标,graphql,relayjs,relay,Graphql,Relayjs,Relay,设想以下GraphQL请求: { books( first:10, filter: [{field: TITLE, contains: "Potter"}], orderBy: [{sort: PRICE, direction: DESC}, {sort: TITLE}] ) } 结果将返回与中继光标信息的连接 光标是否应包含过滤器和orderBy详细信息 这意味着查询下一组数据只意味着: { books(first:10, after:"opaque-cu
{
books(
first:10,
filter: [{field: TITLE, contains: "Potter"}],
orderBy: [{sort: PRICE, direction: DESC}, {sort: TITLE}]
)
}
结果将返回与中继光标信息的连接
光标是否应包含过滤器
和orderBy
详细信息
这意味着查询下一组数据只意味着:
{
books(first:10, after:"opaque-cursor")
}
或者应该重复过滤器
和排序依据
在后一种情况下,用户可以指定不同的过滤器
和/或orderBy
详细信息,这将使不透明光标无效
我在中继规范中找不到与此相关的任何内容。我看到了多种方法,但我发现,使用基于光标的分页,光标只存在于数据集中,更改过滤器会更改数据集,使其无效 如果您使用的是SQL(或者没有基于游标的分页的东西),那么您需要在游标中包含足够的信息,以便能够恢复它。您的光标需要包含所有过滤器/订单信息,并且您需要禁止任何其他过滤
如果他们发送“after”和“filter/orderBy”,则必须抛出一个错误。如果出现用户错误,您可以选择检查参数是否与光标中的参数相同,但根本没有获取不同数据集的“第2页”的用例。我遇到了相同的问题,得出了与@Dan Crews相同的结论。光标必须包含执行数据库查询所需的所有内容,但
LIMIT
除外
当您的初始查询类似于
SELECT *
FROM DataTable
WHERE filterField = 42
ORDER BY sortingField,ASC
LIMIT 10
-- with implicit OFFSET 0
然后你基本上可以(不要在真正的应用程序中这样做,因为SQL注入!)使用这个查询作为你的光标。您只需为每个节点删除限制x
并附加偏移量y
答复:
{
edges: [
{
cursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 0",
node: { ... }
},
{
cursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 1",
node: { ... }
},
...,
{
cursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 9",
node: { ... }
}
]
pageInfo: {
startCursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 0"
endCursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 9"
}
}
然后,下一个请求将使用after:CURSOR,first:10
。然后,您将使用after
参数并设置限制
和偏移
:
LIMIT=first
OFFSET=OFFSET+1
after=endCursor
时,生成的数据库查询如下:
SELECT *
FROM DataTable
WHERE filterField = 42
ORDER BY sortingField,ASC
LIMIT 10
OFFSET 10
如上所述:这只是一个示例,它非常容易受到SQL注入的攻击强>
在现实世界的应用程序中,您只需在光标内对提供的
过滤器
和orderBy
参数进行编码,并添加偏移量
:
函数handleGraphQLRequest(第一个、第二个、过滤器、orderBy){
let offset=0;//如果未提供after,则为初始偏移量
如果(在!=null之后){
//不允许after+筛选器/orderBy的组合!
if(filter!=null | | orderBy!=null){
抛出新错误(“您不能将after与筛选器和/或orderBy组合”);
}
//解析筛选器、orderBy、从光标后的偏移量
cursorData=fromBase64字符串(之后);
filter=cursorData.filter;
orderBy=cursorData.orderBy;
偏移量=游标数据。偏移量;
}
const databaseResult=已执行的DatabaseQuery(
过滤器,//=其中。。。
订购人,//=订购人。。。
首先,//=LIMIT。。。
偏移量//=偏移量。。。
);
const edges=[];//这是结果边数组
让currentOffset=offset;//用于计算每个节点的偏移量
for(让databaseResult.nodes的节点){//遍历数据库结果
currentOffset++;
const currentCursor=createCursorForNode(筛选器、orderBy、currentOffset);
推({
游标=当前游标,
节点=节点
});
}
返回{
边缘:边缘,
pageInfo:buildPageInfo(边、总数、偏移量)//而不是
//为了提供totalCount,您还可以从
//数据库,以检查是否有下一页可用
}
}
//此函数返回光标字符串
函数createCursorForNode(筛选器、orderBy、偏移量){
返回toBase64String({
过滤器:过滤器,
orderBy:orderBy,
偏移量:偏移量
});
}
//用于生成pageInfo对象的函数
函数buildPageInfo(边、总计数、偏移){
返回{
startCursor:edges.length?边[0]。光标:null,
endCursor:edges.length?边[edges.length-1]。光标:null,
hasPreviousPage:偏移量>0&&totalCount>0,
hasNextPage:偏移+边。长度<总计数
}
}
游标的内容主要取决于您的数据库和数据库布局
上面的代码模拟了带有限制和偏移量的简单分页。但是你当然可以(如果你的数据库支持的话)使用其他东西。与此同时,我得出了另一个结论:我认为你是否使用一个多功能游标,或者你是否对每个请求重复筛选和orderBy
,其实并不重要
基本上有两种类型的游标:
(1.)可以将光标视为“指向特定项的指针”。这样,过滤器和排序可以更改,但光标可以保持不变。有点像quicksort中的pivot元素,其中pivot元素保持不变,并且周围的所有东西都可以移动
像这样工作。这里的光标
只是指向数据集中特定项的指针。但是,filter
和orderBy
可以独立更改
这种风格的游标的实现非常简单:只需concat每个可排序字段。完成。示例:如果您的实体可以按price
和title
排序(当然还有id
,因为您需要一些唯一的字段作为平分符),则光标始终由{id,price,title}
组成
(2.)另一方面,“一体式光标”的作用类似于“指向过滤和排序结果集中的项目的指针”。它的好处是,你可以编码你想要的任何东西。Th