What is the best approach for adding variable rows to a Postgres junction table: should you concatenate a query string, utilize multiple queries, or explore alternative methods

Below is the code snippet for handling a variable-length list of tags and inserting data into the database:

// JSON object from req.body  
{
    "title": "title",
    "reference": "1213",
    "noteType": "type_1",
    "tags": [3, 4], 
    "text": "Lorem ipsum dolor sit amet."
}      

// Inserting data into notecards table and retrieving the ID
const response = await db.query(`insert into notecards( 
        title, 
        reference, 
        note_type, 
        main_text
    ) values ( 
        $1, 
        $2, 
        $3, 
        $4 
    ) returning notecard_id;`, [
        title,
        reference,
        noteType,
        text
])
const notecard_id = Number(response.rows[0].notecard_id);

// Adding records to junction table using the ID      
await db.query(`insert into tags_notecard( 
        tag_id, 
        notecard_id
    ) values 
        ( $1, $2 )
        ( $3, $4 );`, 
    [
        tags[0], notecard_id,
        tags[1], notecard_id 
])  

Since tags is dynamic in length, there are two possible approaches mentioned below:

  • Iterating over the tags array and calling separate queries for each record insertion.
  • Concatenating all values into a single query string and sending one parameterized query with multiple sets of values.

The first approach involves making multiple requests by looping through the tags array. This may lead to performance issues if there are constraints on input/output operations:

for (let i = 0; i < tags.length; i++) {
        await db.query(`insert into tags_notecard(tag_id, notecard_id) 
            values ( $1, $2 );`, [tags[i], notecard_id])
    }

Alternatively, the second approach requires constructing a concatenated query string and parameters list for efficient insertions into the junction table:

queryString = "insert into tags_notecard(tag_id, notecard_id) values"
paramsList = []
for (let i = 0, j =1 ; i < tags.length; i++, j+=2) {
     if (i !== tags.length - 1) {
          queryString = queryString + "($" + (j) + ", $" + (j+1)+ "),";
     } else {
         queryString = queryString + "($" + (j) + ", $" + (j+1)+ ");";   
     }
     paramsList.push(tags[i]);
     paramsList.push(notecard_id);
}
await db.query(queryString, paramsList);

Are these strategies efficient for scenarios where there are significant I/O constraints? Are there superior methods that can be employed in such situations?

Answer №1

To efficiently insert data into the database, I would utilize the jsonb data type along with specific functions to execute all the inserts in a single statement:

with input_data as (
  select '{
    "title": "title",
    "reference": "1213",
    "noteType": "type_1",
    "tags": [3, 4], 
    "text": "Lorem ipsum dolor sit amet."
  }'::jsonb as req_body
), insert_notecard as (
  insert into notecards (title, reference, note_type, main_text)
  select req_body->>'title', req_body->>'reference', req_body->>'noteType',
         req_body->>'text'
    from input_data
  returning notecard_id
), insert_tags as (
  insert into tags_notecard (tag_id, notecard_id)
  select t.tag_id::int, n.notecard_id
    from insert_notecard n
         cross join input_data i
         cross join lateral 
           jsonb_array_elements_text(i.req_body->'tags') t(tag_id)
  returning *
)
select * from insert_tags;

Explore working example here

Answer №2

Passing an array value as a parameter and using the unnest function in your query:

await database.query(
  `INSERT INTO tags_notecard(tag_id, notecard_id)
  SELECT unnest($1::int[]), $2;`, 
  [tagValues, cardId]
);  

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

Does the angular scope binding using the &(ampersand) operator only bind once or repeatedly?

Is the angular scope binding &(ampersand) a one time binding? I see it referred to as a one-way binding, but is it also one-time? Let's say I have: <my-custom-directive data-item="item" /> And my directive is declared as follows: .direct ...

Incrementing a variable based on a condition in JavaScript

Currently, I am working on a project where I have a variable called "total" that needs to be assigned a number (or price) and then incremented when certain options are selected or checked. Below is the code that I have developed up to this point. This sni ...

Occasional issue with Bootstrap where jQuery is required for JavaScript

Recently I have started implementing requirejs in my project, but I have encountered a persistent issue that I am unable to resolve. The error message "Bootstrap's JavaScript requires jQuery" randomly appears when I load my application. Below are the ...

Guide on fetching data from a database using Node Js in a hierarchical structure

I am currently developing a NodeJs backend code to retrieve data from the database. The desired structure of the data should look like this: data = [{ name: "Admin", id: '1', children: [ { name: "Admin", id: "1& ...

How can you verify the correctness of imports in Typescript?

Is there a way to ensure the validity and usage of all imports during the build or linting phase in a Typescript based project? validity (checking for paths that lead to non-existent files) usage (detecting any unused imports) We recently encountered an ...

Encountering a problem when attempting to send object data to my MongoDB database within my Node.js application

I am currently using Postman to post data. A sample is provided below, but afterwards I am encountering an error that I cannot seem to understand. I would appreciate it if someone could assist me with this issue. Error: order validation failed: Orditems.0 ...

Utilize closure to save and retrieve state within separate files

Can closure be utilized as an intermediary function between two separate files? In my test code, I am exploring the idea of using closure to store state in one file (index.js) and then accessing that closure in another file (router.js). Coming from a Java ...

Determine the dropdown list value by analyzing the final two variables in a textfield

In my textfield, car registration numbers are meant to be entered. These registrations are based on years in the format GT 74454 12, with the last two digits "12" representing the year 2012. I am looking for a script that can automatically detect the last ...

Angular application parametrization

My application consists of an Angular front-end, an app layer, and a DB layer. The architecture can be seen in this image. To serve the JS front-end bits to the client and proxy requests from the client to the app layer, I am using an nginx instance. If I ...

Using Regular Expressions in JavaScript to verify if an element from an array is contained within a string

Looking for a simple JavaScript code for a Vue application that will split the string into an array and check if any value is present in a different string. Here's what I have: let AffiliationString = " This person goes to Stony Brook" ...

The resolveMX function in Google Cloud Functions is encountering issues when trying to process a list of domains

Here is the task at hand. I have a large list of domains, over 100,000 in total, and I need to iterate through them using a foreach loop to resolve MX records for each domain. Once resolved, I then save the MX records into another database. Below is the c ...

Steps for restricting API access to a specific domain

I am relatively new to NodeJS and Express, and I have a question regarding securing an API endpoint without requiring a traditional login process. The specific context is a web3 application where the only information available from the user is their public ...

What steps can I take to address this Material UI alert and deliver a solution that adds value?

I am currently working on fetching API data (specifically category names) from the back-end (Node.js) to the front-end (React). My main objective right now is to populate a Select component from Material UI. To fetch the API data, I am utilizing Express an ...

Retrieving selected item values in Angular 2 using ng2-completer

Recently, I decided to experiment with a new autocompleter tool that is unfamiliar to me: https://github.com/oferh/ng2-completer. I successfully imported it and it seems to be functioning properly. My current goal is to retrieve the values of the selecte ...

Leveraging a Mongoose Schema Method within a Exported Mongoose Model

Lately, I've been developing an authentication system that is designed to either create a new user if no user with a specific ID exists OR retrieve a user with an existing ID. Through my exploration, I discovered that it's possible to determine w ...

Graph is not showing up when navigating through page

On my List page (List.Html), users can select multiple rows to display the data in a chart using C3. However, when clicking on the compareList() button to navigate to the Chart page (Chart.Html), the chart does not display properly. It seems that the chart ...

Sharing environment variables between a React app and an Express.js server that hosts it as a static site can be achieved by setting

My static site react app is hosted under an express server project in a folder called client/build. The oauth redirect uris point to the express server for token retrieval. The react app redirects users to the oauth endpoint, which is also referenced by th ...

Adding text chips to a text field in Vuetify - A simple guide

I have successfully integrated a text field with vuetify and now I am looking to incorporate chips into it. Currently, chips are only added if the entered text matches a specific pattern (such as starting with '{' and ending with '}'). ...

Creating a conditional property in TypeScript based on an existing type - a comprehensive guide

Imagine if I had the following: type Link = { text: string; link: string; } interface BigLink extends Link { some: number; something: string; else: string; } However, there's a variable that shares all these properties except for the fact ...

Can Ember store in Route handle Post requests?

Is there a way to use ember store functionality similar to this.store.findAll('report') for making POST requests with postObj in my route? Also, how should I handle the response received from these requests? Right now, I am sending ajax POST requ ...