"Perform an upsert operation with TypeORM to create a new entry if it

Is there a built-in feature in TypeORM to handle this scenario efficiently?

let contraption = await thingRepository.findOne({ name : "Contraption" });

if(!contraption) // Create if not exist
{
    let newThing = new Thing();
    newThing.name = "Contraption"
    await thingRepository.save(newThing);
    contraption = newThing;
}

Or perhaps something like this would work better:

let contraption = await thingRepository.upsert({ name : "Contraption" });

Answer №1

In a recent post, Tomer Amir highlighted a partial solution for implementing a real upsert in TypeORM. Additionally, there is an ongoing feature request on the TypeORM repository related to this:

TypeORM upsert feature request

The existing partial solution involves the following code snippets:

await connection.createQueryBuilder()
        .insert()
        .into(Post)
        .values(post2)
        .onConflict(`("id") DO NOTHING`)
        .execute();

await connection.createQueryBuilder()
        .insert()
        .into(Post)
        .values(post2)
        .onConflict(`("id") DO UPDATE SET "title" = :title`)
        .setParameter("title", post2.title)
        .execute();

Prior answers focused on the "update" approach rather than true upsert functionality:

An alternative method already exists: Repository<T>.save(), which handles both inserts and updates according to its documentation:

Saves all given entities in the database. If entities do not exist in the database then inserts, otherwise updates.

However, when id or unique fields are not specified, the save method may not recognize existing database objects.

Therefore, achieving upsert in TypeORM involves utilizing the following code snippet:

let contraption = await thingRepository.save({id: 1, name : "New Contraption Name !"});

Answer №2

If you stumble upon this information in 2021, keep in mind that the Repository.save() method in Typeorm will perform an update or insert operation if it detects a match with a primary key. This functionality is also applicable when using sqlite.

According to the documentation:

/**
 * Saves all provided entities in the database.
 * If the entities do not exist in the database, they will be inserted; otherwise, updated.
 */

Answer №3

2023 Update

New feature alert: Introducing the upsert method!

await this.yourRepository.upsert({name: 'John'}, ['id']) // assuming id is unique

Dealing with constraints on multiple columns:

To define a constraint, use the Unique decorator

@Entity()
@Unique('constraint_name', ['col_one', 'col_two'])

Then you can utilize the upsert method in your code.

await this.yourRepository.upsert({name: 'John'}, ['constraint_name'])

Answer №4

For avoiding duplicates in MySQL and Postgres, you can utilize the INSERT IGNORE method:

await connection.createQueryBuilder()
        .insert()
        .into(Post)
        .values(post)
        .orIgnore()
        .execute();

Answer №5

If you're facing issues with the ONCONFLICT feature in MySQL, this solution might come in handy. Found on Github

await getConnection()
  .createQueryBuilder()
  .insert()
  .into(GroupEntity)
  .values(updatedGroups)
  .orUpdate({ conflict_target: ['id'], overwrite: ['name', 'parentId', 'web', 'avatar', 'description'] })
  .execute();

Answer №6

If you're using Postgres and TypeORM and need to upsert multiple records, you can access the row you want to update/insert by utilizing the excluded keyword.

const articles = [{ id: 1, title: "First Article" }, { id: 2, title: "Second Article" }];

await connection.createQueryBuilder()
        .insert()
        .into(Article)
        .values(articles)
        .onConflict(`("id") DO UPDATE SET "title" = excluded."title"`)
        .execute();

Answer №7

This method has proven effective for me.

I incorporated the solution provided by @DedaDev.

Your specific entity:

@Entity()
@Unique('constraint_name', ['id'])

When it comes to your service:

await this.yourRepository.upsert(
  {
    id: uuid,
    key1: value1,
    ...
  },
  {
    skipUpdateIfNoValuesChanged: true, // If true, postgres will skip the update if no values would be changed (reduces writes)
    conflictPaths: ['id'], // column(s) name that you would like to ON CONFLICT
  },
);

Answer №8

Latest in 2021: TypeORM's version 0.2.40 introduces native upsert support

Learn more about the upsert feature in TypeORM here.

Answer №9

By harnessing the power of NestJS and TypeORM in the year 2024, you have the capability to utilize the upsert function to effectively manage all potential edge cases that may arise.

Imagine a scenario where you are working with an entity named Thing, which consists of attributes like name and color.

@Entity("thing")
@Unique(["name", "color"])
export class Thing {
  @PrimaryGeneratedColumn()
  id: string;

  @Column()
  name: string;

  @Column()
  color: string;

  // more properties can be added here
}

The challenge occurs when the id of the Thing entity is interconnected with various tables in your database, resulting in potential foreign key constraint violations.

You can seamlessly address this issue by implementing the upsert feature along with specific configuration options.

Here's an example implementation demonstrating how you can use upsert with detailed settings:

await repository.upsert(
  [
    { name: "a red thing", color: "red" },
    { name: "a blue thing", color: "blue" },
  ],
  {
    conflictPaths: ["name", "color"],
    skipUpdateIfNoValuesChanged: true,
    upsertType: "on-conflict-do-update",
  }
);

If you encounter any challenges despite this approach, you can resort to a fail-safe method utilizing the following code snippet:


const repository = dataSource.getRepository(Thing);

await repository
    .createQueryBuilder()
    .insert()
    .into(Thing)
    .values([
    { name: "a red thing", color: "red" },
    { name: "a blue thing", color: "blue" },
    ])
    .orUpdate(["name", "color"])
    .orIgnore()
    .execute();

Answer №10

A new tool is available to integrate with TypeORM for simplifying this process, you can find it here.

Answer №11

If you're looking to utilize the "preload" method within the Repository class, check out this link for more information: https://typeorm.delightful.studio/classes/repository_repository.repository.html#preload

The "preload" method creates a new entity based on the provided JavaScript object plan. If the entity already exists in the database, it will be loaded along with related data, then all values will be replaced with those from the new object. The updated entity is essentially the original entity from the database with updated properties. It's important to note that the object must have an entity id or primary key to locate the entity. If no entity is found with the given id, undefined will be returned.

Just keep in mind that, as mentioned earlier, you can only search by ID using this method.

Answer №12

Below is a standard code snippet for handling upsert operations:

async upsertRecord(createDtoGeneric, read: boolean = true) {
    const pk = createDtoGeneric.getPK()
    // Uncomment the lines below if the primary key is not an auto-generated column
    // if (!createDtoGeneric[createDtoGeneric.getPK()])
    //     createDtoGeneric.initPK()
    const upsertResponse = await this._repo.upsert(createDtoGeneric, { conflictPaths: createDtoGeneric.getConflictPaths(), skipUpdateIfNoValuesChanged: true, upsertType: 'on-conflict-do-update' })
    if (read) {
        delete createDtoGeneric[pk]
        return await this.findOneByQuery(createDtoGeneric)
    }
    else
        return upsertResponse;
}

Answer №13

Include this in your entity as the user

@OneToMany(type => Post, post => post.user, {
        cascade: true
    })
    posts: Post[];


export const saveAllPosts = async (req: Request, res: Response) => {
    const userRepository = getManager().getRepository(User);
    const postRepository = getManager().getRepository(Post);
    let i;
    let newUsers:any = [];
    let  newUser:any = {};
    let  newPost:any = {};
    for(i=1; i<=6; i ++) {
        newUser = await userRepository.findOne({ 
            where: { id: i} 
        });
        if(typeof newUser == "undefined") {
            newUser = new User();
            console.log("insert");
        } else  {
            console.log("update");
        }           
        newUser.name  = "naval pankaj test"+i;   

        newPost = await postRepository.findOne({ 
            where: { userId: i} 
        });
        if(typeof newPost == "undefined") {
            newPost = new Post();
            console.log("post insert");
        } else  {
            console.log("post update");
        }
        newPost.title = "naval pankaj add post title "+i;
        newUser.posts = [newPost];
        newUsers.push(newUser);     
    }
    await userRepository.save(newUsers);  
    res.send("complete");
};

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

How can the value of a number in Angular be changed without altering its original value?

Imagine having the initial number 100. If I enter 50 in another input, it should add 50 to 100. However, if I then change the value from 50 to 80, the total should be 180 and not 230. The goal is always to add numbers to the original sum, not the new valu ...

An infinite number of data requests are initiated asynchronously within a loop

When using Angular with TypeScript, I have the following component class: @Injectable() @Component({ selector: 'app-mycomponent', templateUrl: './mycomponent.component.html' }) export class MyComponent implements OnInit{ p ...

Utilizing event listeners with image elements in React for interactive typing experience

When I attempt to type the event as React.ChangeEvent<HTMLImageElement> in order to make the e.target.src work, I encounter the following error messages in the imageFound and ImageNotFound functions: Type '(evt: React.ChangeEvent) => void&a ...

Facing a challenge with handling HTTP data in a TypeScript-based Angular web application

I am currently working on developing a web application using Angular and the SpringMVC Framework. One of the tasks I'm facing is loading a list of users (referred to as "consulenti" in the code). While the backend HTTP request works fine, I encounter ...

Leverage a nearby module with a local dependency

My current challenge involves integrating a local library into my project. I have been following two tutorials: how to create a library and how to consume a local library. Despite having a well-structured sample library with package.json and index.ts, I am ...

I am encountering a problem with my component as the Angular Directive is missing

Recently, I incorporated a customized directive into my Angular app to allow file uploads via drag and drop. However, I encountered an issue where the command line kept throwing an error stating that my function does not exist within my component. Propert ...

Only one choice for discriminated unions in react props

Looking to create a typescript type for react component props, specifically a basic button that can accept either an icon prop or a text prop, but not both. My initial attempt with a discriminated union didn't quite produce the desired outcome: inter ...

Angular 8: Implementing functionality for the Parent Component to detect when the User clicks outside of the Child Component Textbox

I am working on a scenario where I have a Parent Component and a Child Component containing a Formbuilder and a ZipCode textbox. Is there a way to notify the Parent Component when the user clicks out of the Child Component Textbox? I need to trigger some ...

Decoding enum interface attribute from response object in Angular 4 using typescript

From an API response, I am receiving an enum value represented as a string. This enum value is part of a typescript interface. Issue: Upon receiving the response, the TypeScript interface stores the value as a string, making it unusable directly as an en ...

When transitioning from component to page, the HTTP request fails to execute

I have created a dashboard with a component called userInfo on the homepage. This component maps through all users and displays their information. Each user has a display button next to them, which leads to the userDisplay page where the selected user&apos ...

The method this.$el.querySelector does not exist

The data retrieved from the database is inserted into the input fields and submitted as a form. This data is an object that passes the value to the database. However, when I trigger this form, an error occurs. See example of the error <input id=" ...

Issue: An object with keys {} is not suitable as a React child, causing an error

I am new to TypeScript and seeking help from the community. Currently, I am working on a to-do list project where I am using React and TypeScript together for the first time. However, I encountered an error that I cannot decipher. Any assistance would be g ...

Encountering unexpected errors with Typescript while trying to implement a simple @click event in Nuxt 3 projects

Encountering an error when utilizing @click in Nuxt3 with Typescript Issue: Type '($event: any) => void' is not compatible with type 'MouseEvent'.ts(2322) __VLS_types.ts(107, 56): The expected type is specified in the property ' ...

What could be causing the error when my file is running?

Whenever I attempt to run a file using the command node database.ts, an error pops up. Can someone help me identify what's wrong with my syntax? This is how the file appears: import { Sequelize } from 'sequelize-typescript'; export const ...

Triggering JSON schema validation event in React's Monaco Editor

I am interested in implementing custom JSON schema validation in my Monaco editor setup. Here is the current configuration: <MonacoEditor language="json" value={jsonValue} editorWillMount={(monaco) => { monaco.languages.json.jsonD ...

Is it considered bad form to utilize nearly identical for loops in two separate instances within Angular 6?

I am working on creating two lists for a roster. The first list will display the current members of this year, while the second list will show if individuals have been excused for this year. After analyzing my code, I realized that I am using two identic ...

Tips for parsing text responses in React to generate hyperlinks and emphasize specific words

I'm currently tackling a React project and facing an interesting challenge. I have a text response that needs to be parsed in a way that all URLs are automatically turned into clickable hyperlinks (using anchor tags). Moreover, there's a requirem ...

Is there a way to retrieve the number of swipe up interactions from Instagram story insights using the graph API

Is there a way to retrieve the swipe up count displayed in Instagram insights? Since Facebook does not provide this data through their Graph API, how can I access it? I have already tried scraping without success and I am looking for a solution using eith ...

Leveraging CustomPipe with ngModel in Angular 7 and beyond

In my application, I am facing an issue with a date calendar picker input that is storing dates on a server and returning them onInit. The problem arises when the date is not stored or picked, as it returns 01/01/0001 numbers. My goal is to have the input ...

Having trouble uploading a pdf file into a .tsx file

As a beginner in learning TypeScript, I recently embarked on building a portfolio website using React JS and TypeScript. However, I encountered a problem when trying to import a PDF file from my images into the resume.tsx file within my project folder. htt ...