Retrieve a collection of users along with their most recent two entries using TypeORM and SQL

What is the best approach to retrieve a list of users with their last two visited locations using SQL query?

user-table

id  name    
xxx  a
xyx  b
zzz  e

visitedlocation-table

id   startDate userID  location  
1.      1/2/21     xxx    USA
2.      1/3/21     xxx    UK
3.      1/2/21     xyx    AR
4.      1/3/21     xyx    USA
5.      1/5/21     zzz    USA
6.      1/6/21     xxx    IN

Desired output should be structured like:

[
  {
    id: "xxx",
    name: "a",
    lastVisits: [
      {
        id: "6",
        startDate: "1/6/21",
        location: "IN"
      },
      {
        id: "2",
        startDate: "1/3/21",
        location: "UK"
      }
    ]
  },
  {
    id: "xyx",
    name: "b",
    lastVisits: [
      {
        id: "4",
        startDate: "1/3/21",
        location: "USA"
      },
      {
        id: "3",
        startDate: "1/2/21",
        location: "AR"
      }
    ]
  },
  {
    id: "zzz",
    name: "b",
    lastVisits: [
      {
        id: "5",
        startDate: "1/5/21",
        location: "USA"
      }
    ]
  }
]

I am currently utilizing TypeORM and have established a one-to-many relationship between the user entity and the "visited location" table

repository
.createQueryBuilder('user)
.leftJoinAndSelect(
  'user.visitedLocation',
  'visitedLocation',
  'visitedLocation.userId = user.id'
)
.getRawMany();

Although I attempted the provided query, it retrieves all visited locations instead of just the last 2. If achieving this in query builder proves challenging, kindly suggest an alternative SQL query.

Answer №1

If you want to rank your rows and only retrieve the last two of them, consider using dense_rank() function.

SELECT userID, startDate, location 
FROM 
(
     SELECT a.id as userID, b.startDate, b.location,
      --this will group the rows by user_id and then rank them based on startDate   
      DENSE_RANK() OVER(PARTITION BY b.userID ORDER BY b.startDate DESC) as 
                      row_rank 
      FROM users_table a
           INNER JOIN locations_visited b
           ON (a.id = b.userID)
 )T WHERE row_rank <=2 -- fetch only the first two rows

You can find inspiration from the aforementioned logic. Additionally, I will share a solution that provides JSON-based output.

Edit

WITH user_visits AS
(
SELECT userID, name, id, startDate, location 
FROM 
(
     SELECT a.id as userID,a.name,b.id, b.startDate, b.location,
      --this will group your rows by user_id and then rank them based on startDate   
      DENSE_RANK() OVER(PARTITION BY b.userID ORDER BY b.startDate DESC) as 
                      row_rank 
      FROM users_table a
           INNER JOIN locations_visited b
           ON (a.id = b.userID)
 )T WHERE row_rank <=2 -- fetch only the first two rows
)
SELECT jsonb_pretty(array_to_json(array_agg(row_to_json(t)))::jsonb)
FROM(
SELECT userid as id, name, 
            (
                    SELECT array_to_json(array_agg(row_to_json(d))) 
                        FROM(
                                SELECT id,startdate,location
                                    FROM user_visits b
                                WHERE b.userid = u.userid
                        )d
            ) as lastVisits
FROM user_visits u
GROUP BY userid,name
ORDER BY userid
)t;

Result of the above query:

[
    {
        "id": "xxx",
        "name": "a",
        "lastvisits": [
            {
                "id": 6,
                "location": "IN",
                "startdate": "2021-06-01"
            },
            {
                "id": 2,
                "location": "UK",
                "startdate": "2021-03-01"
            }
        ]
    },
    {
        "id": "xyz",
        "name": "b",
        "lastvisits": [
            {
                "id": 4,
                "location": "USA",
                "startdate": "2021-03-01"
            },
            {
                "id": 3,
                "location": "AR",
                "startdate": "2021-02-01"
            }
        ]
    },
    {
        "id": "zzz",
        "name": "e",
        "lastvisits": [
            {
                "id": 5,
                "location": "USA",
                "startdate": "2021-05-01"
            }
        ]
    }
]

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

Challenges with Comparing Dates in MongoDB

I am currently using Mongoose to retrieve data based on a specific date from my database. Specifically, I am trying to fetch any account that has not been accessed for more than an hour. However, when executing the query below, I am not receiving any resu ...

Installing npm on tiny core linux can be accomplished by following a few simple steps

After successfully installing Node.js using appbrowser-cli on my system, I noticed that npm was not installed. How can I go about installing npm on TinyCore Linux? I have attempted several solutions but none have been successful so far. ...

Retrieve the latest inserted ID in a Node.js application and use it as a parameter in a subsequent query

I am currently working with an SQL database that consists of two tables, namely club and players. These tables are connected through a one-to-many relationship. Although the query in my node.js code is functioning properly, I am facing an issue retrieving ...

Can asynchronous programming lead to memory leakage?

I'm wondering about the potential for memory leaks in asynchronous operations, specifically within Javascript used on both frontend and backend (node.js). When the execute operation is initiated, a delegate named IResponder is instantiated. This dele ...

Why isn't the transparency feature in graphicsmagick working?

Currently, I am utilizing the graphicsmagick npm package which can be found at https://www.npmjs.com/package/gm. In my attempt to write a piece of code similar to the one below, I am struggling to make it function properly with stream. The image file myimg ...

MongoDB document queries that do not consider timezones

I have some files with dates saved in various time zones' offsets. [ { "ac":ISODate("2019-09-09T18:30:00.000Z") }, { "ac":ISODate("2019-09-09T12:00:00.000Z") }, { "ac":ISODate("2019-09-09T10:00:00.000Z") ...

What is the best way to check a configuration setting in vue.config.js from srcmain.ts?

I am updating my vue application to include code that will automatically redirect from HTTP to HTTPS when accessing the page. (I understand that configuring this in the webserver is a better practice, but it doesn't hurt to be extra cautious) if (loc ...

Node.js local storage/cookie functionality

Running three different apps on Node.js at ports 3000, 3005, and 3007. I need to set a LocalStorage or Cookie variable at port 3000 and access it from the apps running at ports 3005 and 3007. Folder structure: nodep/ |-app.js (runs at port 30 ...

How to effectively handle asynchronous calls in Node.js using readdir and stat functions

My current project involves implementing a post method on the server side to fetch all files within a specified directory (non-recursively). Below is my code snippet. I am encountering challenges in sending back the response (res.json(pathContent);) with ...

Securing Node function parameters in an asynchronous environment

I've been grappling with a pressing question lately, and I just can't seem to find a definitive answer. Let me share with you a Node function that I frequently use. It manages web requests and conducts some input/output operations: function han ...

The request in C++ is failing to reach the intended computer

Trying to utilize libcurl with C++ for sending an HTTP request to a remote host (my friend's computer) over the internet. On the receiving end, Node.js script is used to handle this request. I have successfully tested this code (both C++ and Node.js) ...

Combining JWT authentication with access control lists: a comprehensive guide

I have successfully integrated passport with a JWT strategy, and it is functioning well. My jwt-protected routes are structured like this... app.get('/thingThatRequiresLogin/:id', passport.authenticate('jwt', { session: false }), thing ...

Having trouble deploying my Node.js application on Microsoft Azure

I encountered an issue while trying to deploy my website on Microsoft Azure Linux App Service using Github actions. The project works perfectly fine in Glitch, but I receive errors when trying to run it on Azure. It seems that Azure is attempting to insta ...

Node app experiencing issues with passport authentication request route only in production mode

Currently, I am facing an issue with my MERN app that includes passport for authentication flow. It runs smoothly in development mode but encounters major problems in production mode that I am struggling to resolve. The bug seems elusive and I can't p ...

Streamline Jasmine-Node and express.js with automated processes

After creating a basic Webapp using express.js, testing it with jasmine-node has been smooth. However, I find myself manually starting the server before each test, which is becoming cumbersome. I am looking for guidance on setting up a spec-helper that ca ...

Problem with Angular2, NodeJS, and Passport Integration

At the moment, my Angular2 front-end is running on localhost:3000 while the NodeJS back-end (using KrakenJS) is running on localhost:8000. When I input the credentials and make a call to the this.http.post('http://localhost:8000/login', body, { h ...

Node.js provides a simple and efficient solution for utilizing the same form code for both adding and updating functionality

I'm looking for a solution to save and update data in the following code: Here's the snippet of code that I am referring to: controller.saveData = (req, res) => { const dataToSave= req.body; req.getConnection((err, connection) = ...

How can I execute route-specific middleware in advance of param middleware in Express v4?

Let me share a unique situation in my routing setup where I need to trigger a middleware before the parameter middleware is executed: router.param('foo', function (req, res, next, param) { // Accessing the param value ... next() }) router ...

When the page is finally displayed, the call back for `node express aws s3.listBuckets` function

Get a list of buckets using callback: router.get('/', function(request,response) { s3.listBuckets(function(error, data) { if (error) { console.log(error); } else { console.log(data.Buckets[0].Name);/ ...

What is the best way to show the user's name on every page of my website?

I'm facing an issue where I can successfully capture the username on the home page using ejs after a login, but when transitioning to other pages from the home page, the username is no longer visible. It seems like I am missing some logic on how to ha ...