Tips for implementing pagination in a search result by adjusting the skip and limit values within the same query

While some may argue that this question belongs on programmers.stackexchange.com, after reviewing the Help Center of Stack Overflow, I believe it is a specific programming issue and will likely receive a better response here.

I have developed a webapp using ExpressJS with a Neo4j database backend. On the search screen, I want to leverage Neo4j's relationships. The screen allows users to input values such as manufacturing year, fuel type, gearbox, etc., which are then sent via POST request to ExpressJS where I construct a Cypher query based on these parameters. An example of the query is shown below:

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

Running the above query returns information about three vehicles along with their properties.

https://i.stack.imgur.com/qBdvP.jpg

If there are more than 20 vehicles in the result, I would like to paginate the results using SKIP and LIMIT as shown below:

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

The workflow for this process is as follows:

  • User navigates to the search screen form with various input fields using POST method.
  • User selects options to search based on their preferences.
  • User submits the form triggering a post request to the server.
  • This request is handled by a ROUTE which constructs a Cypher query using the request parameters and runs it against the Neo4j database to retrieve the results.
  • If there are 200 matching vehicles, only 20 are displayed, along with next/previous buttons for pagination.
  • To show additional results, the same query is rerun with an updated SKIP value.

My question is, what is the most optimal way to save the original search request or generated Cypher query so that clicking next/previous pages triggers a rerun using different SKIP values? I aim to avoid making fresh POST requests every time the user changes pages. There are several potential solutions, but I am unsure which is the most performance-friendly:

  1. Create a new POST request with preserved values each time the user clicks next/previous pages (I am concerned about the costliness of multiple POSTs).
  2. Store the original Cypher query in Redis and retrieve it when needed for pagination updates (handling deletion when necessary).
  3. Save the query in a session or temporary storage for quick access (security and efficiency concerns).

If you have encountered this issue before and found an efficient solution, please share your insights on how best to address this problem.

Answer №1

When it comes to optimizing performance, one of the key steps is utilizing Cypher parameters in your Neo4j queries. By separating the query string from dynamic data, you not only mitigate the risk of injection attacks but also enhance performance by allowing Neo4j to cache query plans for repeated use. An example of a query with parameters:

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}

It's important that your javascript library allows passing a separate object down to Neo4j. This object, represented in json format, would contain specific values for the parameters used in the query.

{
  "vgearbox_type": "MANUAL",
  "vcondition": "USED",
  "manufacture_year": 1990,
  "page": 1,
  "per_page": 20
}

While querying the database from Node each time may not pose a significant issue, it's advisable to benchmark the process to determine any potential bottlenecks. Caching can be considered based on your server setup and proximity between the Node app and the DB. Redis caching or browser local storage for per-user basis caching are options, depending on data variability and user behavior.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to displaying query results separately on a single webpage

On my page, I have two distinct sections: 1) A list of regular questions; 2) A top-voted list of popular questions Both of these sections rely on calls to the same backend API, with the only difference being an additional parameter passed for the popular ...

End the HTML page once the Flash (SWF) animation comes to a close

I have successfully exported my flash file to an HTML page. How can I make the page close automatically once the flash animation is finished? While I can use actionscript to stop the animation, I need the entire page to shut down on its own. I attempted u ...

Has Chrome's console disappeared?

After reinstalling Chrome and opening the dev tools with F12, I encountered an error with the following code: console.debug('test'); The error message displayed was Uncaught ReferenceError: console is not defined(…) This issue persisted acro ...

Is there a way to automatically update a webpage?

When two computers, pc1 and pc2, are on the same page and pc1 changes the status of a field, is there a way to update pc2's aspx page without needing to refresh it? ...

Issue with handling .bind in Angular's karma/jasmine tests Angular's karma/j

When writing unit tests for my functions, I encountered an issue with a bound function in the test runner. The problem arose when trying to bind a function to have reference to 'this' inside an inner function. Here is the code snippet in question ...

The error message in Express points to module.js line 550 and states that the module cannot be

I am currently in the process of setting up a basic express application using the code below: const express = require('express'); const app = express() const bodyParser = require('body-parser'); const cookieParser = require('cooki ...

What is the best way to retrieve a value from a function that contains multiple nested functions in Javascript?

The issue at hand is my struggle to extract a value from a nested method and utilize it outside of its parent method. I am aiming for the output of "console.log(someObjects[i].valueChecker);" to display either "true" or "false," but instead, it simply retu ...

What is the process by which React loads and runs JSX content?

What is the method used to identify and handle JSX code? <script src="src/main.js" type="text/babel"></script> ...

Leverage Dropzone functionality in combination with node.js

Just starting out with node.js and experimenting with file uploads using drag and drop. Initially, I created a basic uploader without drag and drop functionality: var http = require('http'); var formidable = require('formidable'); ...

Adjusting the size of tables in raw JavaScript without altering their positioning

I am attempting to adjust the size of a th element without impacting the position of the next th in the row. Specifically, I want the width of the th to influence the width of the next th accordingly, rather than pushing it to the left. Below is the code ...

The import component path in Angular 4/TypeScript is not being recognized, even though it appears to be valid and functional

I'm currently working on building a router component using Angular and TypeScript. Check out my project structure below: https://i.stack.imgur.com/h2Y9k.png Let's delve into the landingPageComponent. From the image, you can see that the path ...

React useState Error: Exceeded maximum re-renders. React enforces a limit on the number of renders to avoid getting stuck in an endless loop

Can someone help me troubleshoot the 'Too many re-renders' error I'm encountering? I've implemented the try, catch method along with React hooks like useState and setState. My goal is to fetch data from an API and display it on a ...

Prevent unauthorized users from accessing a page in a React application

As a novice in the field of software development, I find myself embarking on the journey of creating a React web application tailored for use at a medical clinic. At its core, this application will cater to just two types of users - patients and doctors. ...

The readStream in Node.JS unexpectedly terminates before the writeStream

I'm currently working on a project that involves fetching PDF files from remote servers and immediately sending them back to the clients who made the request. Here is the code snippet I am using: var writeStream = fs.createWriteStream(filename); writ ...

Javascript object attributes

Could you retrieve the value of one object property based on the value of another property? For instance, in an SQL query, is it possible to fetch the id from the object where the object.name equals "somename"? I am trying to obtain the id of a particula ...

Blending synchronous and asynchronous testing with Mocha

There is a function that calculates certain values and informs the user about events using callbacks: function returnAndCallback(callback) { callback(5); // not always called return 3; } Incorporating Mocha and Should.js, a test was created: descri ...

How do I go about adding a specific class to every row within a Vue.js table?

I have an html table structured like this : <tbody> <tr v-for="employee in employees" :key="employee.EmployeeId" @dblclick="rowOnDblClick(emplo ...

Implementing the sticky positioning property to keep a div container fixed at the bottom of the page

As Bootstrap 4 no longer supports .affix, I had to look for an alternative solution to keep a box fixed. I needed a div container to remain fixed as you scroll to it. My current workaround is using: .fixedcard{ position: sticky; top:75%; } However, th ...

Tips for dynamically expanding the interface or type of an object in TypeScript

Currently, I am exploring the integration of PayPal's Glamorous CSS-in-JS library into a boilerplate project that also utilizes TypeScript. Glamorous provides a way to incorporate props into an element as shown below: const Section = glamorous.secti ...

Resolving CORS issues: Troubleshooting communication between a React app and an Express server

After successfully running both the app and server locally, I encountered an issue upon deploying the express server. Whenever I try to make a request, I consistently receive the following error message: "has been blocked by CORS policy: Response to ...