43-Nodejs Course 2023: Database Models: Created At And Updated At Columns
Tags: node, typescript, mongodb, fastify
Published: 2022-11-06 15:15:54

---
title: 43-Nodejs Course 2023: Database Models: Created At And Updated At Columns
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0n3rmym76n5rhfloo41h.png
# Use a ratio of 100:42 for best results.
---

So we saw how we can save our data in the model, but we need to add more details about the saving process like when the document has been created and when it has been updated.

So let's do it.

## Create Method

In our static class `CrudModel` we've the `create` and `update` methods, the `create` method generates a new id before saving the data and returns a new instance of the model.

But what about if we reverse it? we create a new instance with the data and then we just save it!

```ts
// src/core/database/model/crud-model.ts

export default abstract class CrudModel extends BaseModel {
  // ...
  
  /**
   * Create a new record in the database for the current model (child class of this one)
   * and return a new instance of it with the created data and the new generated id
   */
  public static async create<T>(
    this: ChildModel<T>,
    data: Document,
  ): Promise<T> {
    const model = this.self(data);

    await model.save();

    return model;
  }
}
```

See, much cleaner and easier, also it will prevent code duplicate as we don't have to generate the id in both methods in the `create` and `save` methods.

## Update Method

Let's update the `update` method as well

```ts
// src/core/database/model/crud-model.ts

export default abstract class CrudModel extends BaseModel {
  // ...
  
  /**
   * Update model by the given id and return it if found
   */
  public static async update<T>(
    this: ChildModel<T>,
    id: PrimaryIdType,
    data: Document,
  ): Promise<T | null> {
    const model = (await this.find(id)) as any; // silent typescript compiler

    if (!model) return null;

    await model.save(data);

    return model;
  }
}
```

We first get the model by the given id.

If the model is not found, then we return `null`.

Otherwise, we update the model with the given data and return it.

## Replace Method

Let's do the same with the replace method

```ts
  /**
   * Replace the entire document for the given document id with the given new data
   */
  public static async replace<T>(
    this: ChildModel<T>,
    id: PrimaryIdType,
    data: Document,
  ): Promise<T | null> {
    const model = (await this.find(id)) as any;

    if (!model) return null;

    model.replaceWith(data);

    await model.save();

    return model;
  }
```

We replaced the data using the `replaceWith` method and then we save it.

## Upsert method

Now let's update the upsert method

```ts

  /**
   * Find and update the document for the given filter with the given data or create a new document/record
   * if filter has no matching
   */
  public static async upsert<T>(
    this: ChildModel<T>,
    filter: ModelDocument,
    data: Document,
  ): Promise<T | null> {
    let model = (await this.first(filter)) as any;

    // if not exists, create it
    if (!model) {
      model = this.self({ ...filter, ...data });
    } else {
      // update it
      model.replaceWith({ ...filter, ...data });
    }

    await model.save();

    return model;
  }
```

Here is how it works, we first get the first matched model for the given filter, if the model is not found, then we create a new one with the given filter and data.

Otherwise, we update the model with the given data.

## Recapping what we've done

So basically we transformed all of the static operations to act as if we were working with the model directly, this will allow us to put all updates in one place which is the `save` method only.

## Created At And Updated At

Now we need to add the `createdAt` and `updatedAt` fields to the model, so let's do it.

The `createdAt` will be added when the model is being saved as creating, and the `updatedAt` will be updated every time the model is updated and in the `create` process as well.

```ts
// src/core/database/model/model.ts

/**
 * Perform saving operation either by updating or creating a new record in database
 */
public async save(mergedData: Document = {}) {
  this.merge(mergedData);

  // check if the data contains the primary id column
  if (this.data._id) {
    // perform an update operation
    // check if the data has changed
    // if not changed, then do not do anything
    if (areEqual(this.originalData, this.data)) return;

    // update the updated at column
    this.data.updatedAt = new Date();

    await queryBuilder.update(
      this.getCollectionName(),
      {
        _id: this.data._id,
      },
      this.data,
    );
  } else {
    const generateNextId =
      this.getStaticProperty("generateNextId").bind(Model);

    this.data.id = await generateNextId();

    // createdAt Column
    const now = new Date();
    this.data.createdAt = now;
    // updatedAt Column
    this.data.updatedAt = now;

    this.data = await queryBuilder.create(
      this.getCollectionName(),
      this.data,
    );
  }
}
```

So we added the `createdAt` and `updatedAt` columns in the `save` method, and we also updated the `update` method to update the `updatedAt` column.

## 🎨 Conclusion

So we've added the `createdAt` and `updatedAt` columns to the model, and we've also updated the `save` method to update the `updatedAt` column.

We also moved all insertion and updating operations to the `save` method only.

## 🚀 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)