Javascript 如何使用具有不同跳过值和限制值的同一查询对搜索结果进行分页

Javascript 如何使用具有不同跳过值和限制值的同一查询对搜索结果进行分页,javascript,express,neo4j,pagination,redis,Javascript,Express,Neo4j,Pagination,Redis,你们中的一些人可能会认为这是一个问题,但是,在通读了堆栈溢出之后,我相信这是一个特定的编程问题,我更可能在这里得到回答 我有一个webapp,它使用ExpressJS和Neo4j数据库作为后端。我有一个搜索屏幕,在那里我想使用Neo4j的关系的力量。搜索屏幕接受一个或多个值(即制造年份、燃油类型、变速箱等),然后向ExpressJS发出post请求,其中我使用post请求的参数构造一个密码查询,如下所示,作为示例: MATCH (v:VEHICLE),(v)-[:VGEARBOX_IS]-&

你们中的一些人可能会认为这是一个问题,但是,在通读了堆栈溢出之后,我相信这是一个特定的编程问题,我更可能在这里得到回答

我有一个webapp,它使用ExpressJS和Neo4j数据库作为后端。我有一个搜索屏幕,在那里我想使用Neo4j的关系的力量。搜索屏幕接受一个或多个值(即制造年份、燃油类型、变速箱等),然后向ExpressJS发出post请求,其中我使用post请求的参数构造一个密码查询,如下所示,作为示例:

MATCH
  (v:VEHICLE),(v)-[:VGEARBOX_IS]->(:VGBOX{type:'MANUAL'}),
  (v)-[:VCONDITION_IS]->(:VCONDITION{condition:'USED'})  
WITH DISTINCT v
WHERE  v.manufacture_year = 1990
MATCH (v)-[r]->(info)
RETURN v AS vehicle, COLLECT({type:type(r), data:info}) AS details
假设运行上述查询,将返回以下三个车辆及其属性

如果结果超过20辆车,那么我想对结果进行分页,我知道这是如何工作的,我们使用SKIP and LIMIT,如下所示:

MATCH
  (v:VEHICLE)
OPTIONAL MATCH (v)-[r:VFUEL_TYPE|:VGEARBOX_IS|:VHAVING_COLOR|...]->(info)
RETURN
  v.vehicle_id AS vehicle_id,
  v.engine_size AS engine_size,
  v.published_date AS published_date,
  COUNT(v) AS count,
  COLLECT({type:type(r), data:info}) as data
ORDER BY v.published_date DESC
SKIP 20
LIMIT 16
这是工作流程

  • 用户导航到搜索屏幕,这是一个带有POST方法和各种输入字段的表单
  • 用户选择一些他/她希望搜索的选项
  • 然后,用户提交表单,表单向服务器发出post请求
  • 该请求由一个路由处理,该路由使用请求的参数来构造如上所示的密码查询。它对Neo4j数据库运行cypher并接收结果
  • 假设有200辆车与搜索结果匹配。然后我只想显示其中的20个结果,并提供下一个/上一个按钮
  • 当用户看到前20个时,他/她希望看到下一个20,也就是说,我必须重新运行用户最初提交的相同查询,但跳过值为20(当用户导航到下一页时跳过值不断增加20,当移动到上一页时递减20)
我的问题是,保存搜索请求(或原始请求生成的密码)的最佳方法是什么,这样当用户单击下一页/上一页时,我就可以使用不同的跳过值重新运行原始搜索密码查询?我不想每次用户转到下一页/上一页时都发出新的POST请求。此问题可以通过以下方式解决,但不确定哪一种性能更友好

  • 每次用户单击“下一页”或“上一页”时,我都会使用原始请求的保留值发出一个新的POST请求,并重建cypher查询(POST可能会很昂贵-我想避免这种情况,请说明为什么这是更好的选择)
  • 我将原始的cypher查询存储在Redis中,每当用户单击next或previous时,我都会从Redis中检索特定于该用户的查询(需要通过cookie、会话或某种隐藏的uuid进行处理),为SKIP提供新值并重新运行它(不知何故,我必须处理何时从Redis中删除此条目-当用户更改搜索或放弃页面/站点时,应进行删除)
  • 我将查询存储在会话(用户无需登录)或其他提供快速访问(不确定是否安全高效)的临时存储(Redis除外)中

  • 我确信有人遇到了这个问题,并且以一种高效的方式解决了这个问题,这就是我在这里发布这个问题的原因。请告诉我如何才能最好地解决这个问题。

    就性能而言,您绝对应该做的第一件事就是使用。这是一种将查询字符串与动态数据分离的方法。这具有优势您可以防范注入攻击,但这也会提高性能,因为如果您的查询字符串不变,Neo4j可以为您的查询缓存查询计划,并反复使用它。使用参数,您的第一个查询将如下所示:

    MATCH
      (v:VEHICLE),(v)-[:VGEARBOX_IS]->(:VGBOX{type: {vgearbox_type}}),
      (v)-[:VCONDITION_IS]->(:VCONDITION{condition: {vcondition}})  
    WITH DISTINCT v
    WHERE  v.manufacture_year = {manufacture_year}
    MATCH (v)-[r]->(info)
    RETURN v AS vehicle, COLLECT({type:type(r), data:info}) AS details
    SKIP ({page} - 1) * {per_page}
    LIMIT {per_page}
    
    Neo4j的javascript库应该允许您传递一个单独的对象。以下是用json表示的对象的外观:

    {
      "vgearbox_type": "MANUAL",
      "vcondition": "USED",
      "manufacture_year": 1990,
      "page": 1,
      "per_page": 20
    }
    
    我认为每次从节点对数据库进行新的查询并没有什么问题。您应该测试实际需要多长时间才能确定这是否真的是一个问题


    如果您希望通过缓存来解决这一问题,则这取决于您的服务器设置。如果节点应用程序和数据库位于同一台计算机上或彼此非常接近,则这可能并不重要。否则,您可以使用redis根据您要查询的值的组合键进行缓存。如果您考虑的是cach基于每个用户,您甚至可以使用浏览器的本地存储,但用户是否经常反复访问相同的页面?您的数据有多静态?用户之间的数据是否不同?

    感谢cypher参数的建议,我肯定会研究注入问题。关于每次发布新帖子e user转到下一页/上一页,我应该如何保留原始请求中的post值?隐藏字段?会话?我建议在每篇post中发送所有表单参数。它不应该大大增加您的请求大小。这可能是隐藏字段,也可能是javascript的编写方式,具体取决于你正在写这篇文章。如果你使用类似会话的方式,我怀疑你会发现至少还有一个bug,否则你会试图跟踪事情。感谢你花时间回复这篇文章,这是有意义的。