33-Nodejs Course 2023: Database Models: Crud Operations: Update Operations
Tags: node, typescript, mongodb, fastify
Published: 2022-11-03 18:25:10

---
title: 33-Nodejs Course 2023: Database Models: Crud Operations: Update Operations
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
#cover_image: 
# Use a ratio of 100:42 for best results.
---

So, we have created our first method successfully which is the `create` method.

Now let's work with some update operations, let's start with the basic one which is the `update` method.

## Update

The update method will receive an id and an object of data that will be updated in the database and return a new model instance with the data from the database.

```ts
// src/core/database/model/model.ts
import { Collection } from "mongodb";
import connection, { Connection } from "../connection";
import { Database } from "../database";

/**
 * Base Model type that we need to define
 * to tell typescript that we're going to return a child that extends that base model
 * which will be the T (The child class)
 */
type BaseModel<T> = typeof Model & (new () => T);

export default abstract class Model {
  // ...
  
  /**
   * Update the given data to the given id and return a new instance of the model
   */
  public static async update<T>(
    this: BaseModel<T>,
    id: string | number,
    data: Record<string, any>,
  ): Promise<T> {
    // 1- get the query of the collection
    const query = this.query();

    // 2- create a filter object to filter the data by the id
    const filter = {
      _id: id,
    };

    // 3- we'll use findOneAndUpdate to get the record after the update is done
    const result = await query.findOneAndUpdate(
      filter,
      {
        // Update the given data
        $set: data,
      },
      {
        // return the entire updated document after update
        returnDocument: "after",
      },
    );

    // 4- return a new instance of the model with the updated data
    return this.self(result.value as Record<string, any>);
  }
}
```

Pretty much the same as `create` workflow, it receives the `_id` (for now) and the data that will be updated.

Internally, we use [findOneAndUpdate](https://www.mongodb.com/docs/manual/reference/method/db.collection.findOneAndUpdate/#mongodb-method-db.collection.findOneAndUpdate) to update the data and return the updated document.

First we create a filter object that we want to run the update on, then we use `findOneAndUpdate` to update the data and return the updated document.

It accepts three arguments, the first one is the filter we want to search by for the document which will be searching by the _id column, the second argument is an object of the update operations (there are multiple cases that can be used in this one) but we'll only use the `$set` operator, which is a built on operator on MongoDB to tell it to update the given data, the third argument is an object of options, we'll use the `returnDocument` option to tell it to return the updated document after the update is done.

Then we return a new instance of the model with the updated data.

Now let's give it a try

```ts
// src/app/users/routes.ts

setTimeout(async () => {
  const user = await User.create({
    name: "hasan",
    email: "hassanzohdy@gmail.com",
  });

  const updatedUser = await User.update(user.data._id
    {
      name: "hasanZ",
      age: 25,
    },
  );

  console.log(updatedUser.data); // { _id: "12wqedrt42ewqsdefrt5213", age: 25, name: "hasanZ", email: "hassanzohdy@gmail.com"}
}, 4000);
```

As you can see, we created a user, then we updated the name and added a new `field/column` which is `age` of the user and we got the updated user.

Now what if we want to replace the entire document with the new data?

We can do that by using the `replace` method.

## Replace

The previous one we made an update on the document by updating the existing column and added new one, but if we want to replace it entirely with the new data, we can use the `findOneAndReplace` method.

```ts
// src/core/database/model/model.ts
import { Collection } from "mongodb";
import connection, { Connection } from "../connection";
import { Database } from "../database";

/**
 * Base Model type that we need to define
 * to tell typescript that we're going to return a child that extends that base model
 * which will be the T (The child class)
 */
type BaseModel<T> = typeof Model & (new () => T);

export default abstract class Model {
  // ...
  
  /**
   * Replace the given data to the given id and return a new instance of the model
   */
  public static async replace<T>(
    this: BaseModel<T>,
    id: string | number,
    data: Record<string, any>,
  ): Promise<T> {
    // 1- get the query of the collection
    const query = this.query();

    // 2- create a filter object to filter the data by the id
    const filter = {
      _id: id,
    };

    // 3- we'll use findOneAndReplace to get the record after the replace is done
    const result = await query.findOneAndReplace(
      filter,
      data,
      {
        // return the entire updated document after update
        returnDocument: "after",
      },
    );

    // 4- return a new instance of the model with the updated data
    return this.self(result.value as Record<string, any>);
  }
}
```

If you see it is almost the same as the `update` method, the only difference is that we use `findOneAndReplace` instead of `findOneAndUpdate` and we don't use the `$set` operator.

Now let's give it a try

```ts
// src/app/users/routes.ts

setTimeout(async () => {
  const user = await User.create({
    name: "hasan",
    email: "hassanzohdy@gmail.com",
  });

  const updatedUser = await User.replace(user.data._id
    {
      name: "hasanZ",
      age: 25,
    },
  );

  console.log(updatedUser.data); // { _id: "12wqedrt42ewqsdefrt5213", age: 25, name: "hasanZ"}
}, 4000);
```

The main difference is that we don't have the `email` field/column anymore.

## Upsert

Now what if we want to update the document if it exists, or create a new one if it doesn't exist?

We can do that by using the `findOneAndUpdate` method with the `upsert` option.

> The upsert term is a portmanteau of update and insert. It is used to describe the process of updating a document if it exists or inserting a document if it does not.

```ts
// src/core/database/model/model.ts
import { Collection } from "mongodb";
import connection, { Connection } from "../connection";
import { Database } from "../database";

/**
 * Base Model type that we need to define
 * to tell typescript that we're going to return a child that extends that base model
 * which will be the T (The child class)
 */
type BaseModel<T> = typeof Model & (new () => T);

export default abstract class Model {
  // ...
  
  /**
   * Update the given data to the given id or create a new one if it doesn't exist
   */
  public static async upsert<T>(
    this: BaseModel<T>,
    filter: Record<string, any>,
    data: Record<string, any>,
  ): Promise<T> {
    // 1- get the query of the collection
    const query = this.query();

    // 2- we'll use findOneAndUpdate to get the record after the update is done
    const result = await query.findOneAndUpdate(
      filter,
      {
        // Update the given data
        $set: data,
      },
      {
        // return the entire updated document after update
        returnDocument: "after",
        // upsert the document if it doesn't exist
        upsert: true,
      },
    );

    // 4- return a new instance of the model with the updated data
    return this.self(result.value as Record<string, any>);
  }
}
```

The upsert method accepts two arguments, the first one is the filter we want to search by for the document, the second argument is an object of the update operations (there are multiple cases that can be used in this one) but we'll only use the `$set` operator, which is a built on operator on MongoDB to tell it to update the given data.

Then we return a new instance of the model with the updated data.

Now let's give it a try

```ts
// src/app/users/routes.ts

setTimeout(async () => {
  const updatedUser = await User.upsert({
    _id: 'some-id',
  },
    {
      name: "hasanZ",
      age: 25,
    },
  );

  console.log(updatedUser.data); // { _id: "some-id", age: 25, name: "hasanZ", email: "hassanzohdy@gmail.com"
}, 4000);
```

## 🎨 Conclusion

In this article, we learned update update operations, not all of it but the ones that we need for now like normal update, full replace and upsert.

## 🎨 Project Repository

You can find the latest updates of this project on [Github](https://github.com/hassanzohdy/nodejs-2023)

## 😍 Join our community

Join our community on [Discord](https://discord.gg/pb2vmdfhGf) to get help and support (Node Js 2023 Channel).

## 🎞️ Video Course (Arabic Voice)

If you want to learn this course in video format, you can find it on [Youtube](https://www.youtube.com/playlist?list=PLGO8ntvxgiZMJc7RN2lIq9WmMOlWZGzmz), the course is in Arabic language.

## 💰 Bonus Content 💰

You may have a look at these articles, it will definitely boost your knowledge and productivity.

General Topics

- [Event Driven Architecture: A Practical Guide in Javascript](https://dev.to/hassanzohdy/event-driven-architecture-the-best-paradigm-that-i-love-to-work-with-in-javascript-and-node-js-1gnk)
- [Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript](https://dev.to/hassanzohdy/best-practices-for-case-styles-camel-pascal-snake-and-kebab-case-in-node-and-javascript-55oi)
- [After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
](https://dev.to/hassanzohdy/after-6-years-of-practicing-mongodb-here-are-my-thoughts-on-mongodb-vs-mysql-574b)

Packages & Libraries

- [Collections: Your ultimate Javascript Arrays Manager](https://dev.to/hassanzohdy/collections-your-ultimate-javascript-array-handler-3o15)
- [Supportive Is: an elegant utility to check types of values in JavaScript](https://dev.to/hassanzohdy/supportive-is-an-elegant-utility-to-check-types-of-values-in-javascript-1b3e)
- [Localization: An agnostic i18n package to manage localization in your project](https://dev.to/hassanzohdy/mongez-localization-the-simplest-way-to-translate-your-website-regardless-your-favorite-framework-4gi3)

 React Js Packages

- [useFetcher: easiest way to fetch data in React Js](https://dev.to/hassanzohdy/usefetcher-the-easiest-way-to-fetch-data-in-react-45o9)

Courses (Articles)

- [React Js: Let"s Create File Manager With React Js and Node Js](https://dev.to/hassanzohdy/lets-create-a-file-manager-from-scratch-with-react-and-typescript-chapter-i-a-good-way-to-expand-your-experience-5g4k)