You Don't Know About Populate
Tags: mongodb, node, database
Published: 2021-06-06 09:23:41

To Understand populate, you have to understand the relation between collections.

Consider a library where we have

- **A Collection Of Books** which is consist of `id`, `name`, `author` and `another informational fields`.
- **A Collection Of Users** which is consist of `id `, `name` and `other stuff`
- **A Collection Of Issue** which is consist of user and books, just for now ignore other stuff

## ![Database Collection Showing User And Books](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6fdt7s34viwirtxih33.jpg)

---

## Lets Begin

Think of how we can store **Issue Collection** record

- **By saving user data and book data**

  ```JSON
  [
    {
      "user": {
        "name": "John",
        "_id": "65230asa434r345d34kd3wbb",
        "address": "Noida",
        "email": "john@example.com"
      },
      "book": {
        "name": "Harry Potter",
        "_id": "6b6s6a9d6fj87s8978s86s7s",
        "author": "J.K. Rowling",
        "publication": "XYZ"
      }
    }
  ]
  ```

  the problem with this approach is you end up with collecting duplicate data(User is also present in User collection and same with Books). This makes your database containing duplicate fields and hard to maintain.

### But what makes it hard? I will access record fields easily!

My friend, this is hard because imagine if user has updated this email field or, the books field have been edited then we have to update records two times in `Issues` Collection and `Books` or `User` Collection.

To make database redundant, we should move to second approach

- **By Saving `User _id` and `Book _id` in `Issues` Record**

  ```Javascript
  [
    {
      "user": ObjectId("65230asa434r345d34kd3wbb"),
      "book": ObjectId("6b6s6a9d6fj87s8978s86s7s"),
    }
  ]
  ```

  with this approach we are storing a reference of user and book in their respective collections.

### So How I Get Records? This Looks To Complex!!

  My friend, here the populate comes to aid(_Why They called it `Populate` because finds data with their unique id and replace the ObjectId).

#### Advantages

  - Database is not redundant.
  - Updating records in easy.

## Let's Implement This

Create Book and User models

```Javascript
  const { Schema, model } = require('mongoose');

  const userSchema = new Schema({
    name: String,
    address: String,
    email: String,
  });

  const User = model('User', userSchema);
```

```Javascript
  const { Schema, model } = require('mongoose');

  const bookSchema = new Schema({
    name: String,
    author: String,
    publication: String,
  });

  const Book = model('Book', bookSchema);
```

Lets add some Documents('same as Records') To Collection

```Javascript
  const john = await User.create({ // User.create() is equivalent to new User().save()
    name: "John",
    address: "Noida",
    email: "john@example.com"
  })
```

```Javascript
  const harryPotter = await Book.create({
    name: "Harry Potter",
    author: "J.K. Rollings",
    publication: "XYZ"
  })
```

## Now User Issue a book from library

So how we do it?
Here comes the populate to aid

```Javascript
  const { Schema, model, Types } = require('mongoose');

  const issuesSchema = new Schema({
    user: { type: Types.ObjectId, ref: "User" },
    book: { type: Types.ObjectId, ref: "Book" },
  });

  const Issue = model('Issue', issuesSchema);
```

### What the is `type` and `ref`

- `type`: it is property tells to store the ObjectId of that particular document(document is here User or book)
- `ref`: It is a name of collection to find that ObjectId. Here "User" and "Book" are name of collections we created.

### Let's Issue A Book

**Think John Comes To Library To Issue A Book Harry Potter**
To issue a book we have to create a new Issue

```Javascript
const issuedBook = await Issue.create({ user: john, book: harryPotter });
```

### What's going here

Actually, we are saving john.\_id and harryPotter.\_id value to issue, in database it's look like

```
  { // issuedBook 1
     user: "65230asa434r345d34kd3wbb",
     book: "6b6s6a9d6fj87s8978s86s7s",
  }
  { // issuedBook 2
     user: "65230asa45645r4jjjl3434h",
     book: "6b6s6a9h5j3kh7j38fw4j3k2",
  }
```

_This is how we save to refrences to user and books field_
_There are various ways to save refrences. Check out documentation [here](https://mongoosejs.com/docs/populate.html#saving-refs)_

## How To Populate Records ?

Now, imagine libarian wants to check all issued book records.
Well this is very simple to implement

```Javascript
  const Issue = require('./models/issue');
  // Import Issue model
```

```Javascript
  const issuedBooks = await Issue.find({}).populate('user').populate('book').exec()
```

Let's understand this what does that chain of calls doing

1. `Issue.find({})`: This will find all records in `Issue` Collection. _You can set conditions in find_
2. `populate('user)`: parameter 'user' is same of field which we want to populate. `populate('user')` will find user by thier perspecitve id and replaces `user` field with actual user data.
3. `populate('book)`: same as above, replace book id with actual record
4. `exec()`: This is very important function call. This will execute above all populate operation. If you forgot to call this. Your field will not be populated.

**Note: If During Populate Some Records Are Not Found Then These Records Are Replaced By `null`**

Now `issuedBooks` value be like

```
  { // issuedBook 1
     user: {
        name: "John",
        address: "Noida",
        email: "john@example.com",
        _id: "65230asa434r345d34kd3wbb"
     },
     book: {
       name: "Harry Potter",
       author: "J.K. Rollings",
       publication: "XYZ",
       _id: "6b6s6a9d6fj87s8978s86s7s"
     }
  }
  { // issuedBook 2
     user: {
        name: "Peter",
        address: "Delta",
        email: "peter@example.com",
        _id: "65230asa45645r4jjjl3434h"
     },
     book: {
       name: "Invisible Man",
       author: "Ralph Elipson",
       publication: "ABC",
       _id: "6b6s6a9h5j3kh7j38fw4j3k2"
     }
  }
```

## Conclusion

This seems like a useful tool in being able to define a declarative model for what your data should look like as a result of any query. There are some inherent weaknesses to a lack of true “joins”, but the Mongoose API does an elegant job of optimizing these types of queries under the hood by using poplulate.

I’ve only recently begun using this, so if you know something that I don’t and would like to contribute to the discussion for anyone reading this article, feel free to comment below with any critiques, suggestions, random quotes, or song lyrics. Thanks