34-Nodejs Course 2023: Database Models: Crud Operations: Finding Documents
Tags: node, typescript, mongodb, fastify
Published: 2022-11-03 20:41:17

---
title: 34-Nodejs Course 2023: Database Models: Crud Operations: Finding Documents
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m6y11h9iwt7sdnbpzs6y.png
# Use a ratio of 100:42 for best results.
---

Now we're done with insertions and updates, let's try to find some documents.

## Finding Documents

As we mentioned before, we'll have couple of find methods, one to find by id and another one to find by certain column.

### Finding by Id

Let's start with finding by id. We'll create a new method in our repository.

```ts
// src/core/database/model/mode.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 {
  // ...
  /**
   * Find a document by id
   */
  public static async find<T>(
    this: BaseModel<T>,
    id: string,
  ): Promise<T | null> {
    const query = this.query();

    const result = await query.findOne({ _id: id });

    return result ? this.self(result) : null;
  } 
}
```

What we did here is that we created a new method called `find` that takes an id and returns a promise of the child class or `null` if it doesn't exist.

We're using the `this` keyword to tell typescript that we're going to return a child class of the base model.

Now let's give it a try

```ts
// src/app/users/routes.ts
import User from "./models/user";

setTimeout(async () => {
  const user = await User.find("2wqsdaefqw");

  if (user) {
    console.log(user.data);
  } else {
    console.log("Not Found");
  }
}, 4000);
```

## Finding by Column

Now let's create another method to find by a certain column.

```ts
// src/core/database/model/mode.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 {
  // ...
  /**
   * Find a document by column
   */
  public static async findBy<T>(
    this: BaseModel<T>,
    column: string,
    value: string,
  ): Promise<T | null> {
    const query = this.query();

    const result = await query.findOne({ [column]: value });

    return result ? this.self(result) : null;
  } 
}
```

What we did here is that we created a new method called `findBy` that takes a column and a value and returns a promise of the child class or `null` if it doesn't exist.

Let's give it a try

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

import User from "./models/user";

setTimeout(async () => {
  const user = await User.findBy("email", "hassanzohdy@gmail.com");

  if (user) {
    console.log(user.data);
  } else {
    console.log("Not Found");
  }
```

## Finding All Documents

Now let's create a method to find all documents.

```ts
// src/core/database/model/mode.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 {
  // ...
  /**
   * Find all documents
   */
  public static async list<T>(
    this: BaseModel<T>
    filter: Record<any, string> = {}
  ): Promise<T[]> {
    const query = this.query();

    const result = await query.find(filter).toArray();

    return result.map((item) => this.self(item));
  } 
}
```

What we did here is that we created a new method called `list` that takes a filter and returns a promise of an array of the child class or `array` if it doesn't exist.

Let's give it a try

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

import User from "./models/user";

setTimeout(async () => {
  const users = await User.list();

  console.log(users);

  // finding all users with a certain role
  const admins = await User.list({ role: "admin" });

  console.log(admins);
```

## Finding Documents with Pagination

Now let's create a method to find documents with pagination and get the pagination results.

The pagination concept is that we have a certain number of documents per page and we need to get limited documents per page.

So the result of this method will be split into two parts, the documents and the pagination results.

The pagination results will contain the total number of documents, the total number of pages, the current page, and the number of documents per page (limit).

```ts
// src/core/database/model/mode.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);

/**
 * The result of the paginate query
 */ 
type PaginationListing<T> = {
 /**
  * Results of the query
  */
 documents: T[];
 /**
  * The pagination results
  */
  paginationInfo: {
    /**
     * Limit of the query
     */
    limit: number;
    /**
     * Results of the query
     */ 
    result: number;
    /**
     * Current page of the query
     */ 
    page: number;
    /**
     * total results of the query
     */ 
    total: number;
    /**
     * total pages of the query
     */
    pages: number;
  };
};

export default abstract class Model {
  // ...
  /**
   * Find all documents with pagination
   */
  public static async paginate<T>(
    this: BaseModel<T>,
    filter: Record<any, string> = {},
    page: number,
    limit: number,
  ): Promise<{ data: T[]; total: number }> {
    const query = this.query();

    const result = await query
      .find(filter)
      .skip((page - 1) * limit)
      .limit(limit)
      .toArray();

    const total = await query.countDocuments(filter);

    return {
      data: result.map((item) => this.self(item)),
      paginationInfo: {
        limit,
        result: result.length,
        page,
        total,
        pages: Math.ceil(total / limit),
      },
      },
    };
  } 
}
```

What we did here is that we created a new method called `paginate` that takes a filter, page and limit and returns a promise of an object that contains the data and the pagination info.

We performed two queries here, one to get the data and the other to get the total number of documents for that filter.

The first query we did we used other methods after `find` method, let's see it one by one.

`skip` it receives a number and it will skip that number of documents and return the rest.

The number we passed to it is calculated by the page number and the limit, so if we're on page 1 and limit is 10 then we will skip 0 documents and return the rest, if we're on page 2 and limit is 10 then we will skip 10 documents and return the rest.

The formula is `skip = (page - 1) * limit`

`limit` it receives a number and it will limit the number of documents returned to that number.

Then we return an object that contains the data and the pagination info.

Let's give it a try

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

import User from "./models/user";

setTimeout(async () => {
  const users = await User.paginate({}, 1, 10);

  console.log(users);

  // finding all users with a certain role
  const result = await User.paginate({ role: "admin" }, 1, 10);

  const { data, paginationInfo } = result;

  console.log(data);

  console.log(paginationInfo);
```

## 🎨 Conclusion

Here we illustrated how to find documents either finding a single document by id or by a certain column or finding all documents or `finding documents with pagination`.

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