Extra Step: Writing Posts
Tags: javascript, express, beginners, mongoose
Published: 2020-09-21 22:37:48

In the last article of this series, we did many things:
1- We created two simple forms for creating users and posts with actions to two different routes.
2- We added these routes to our app.
3- We defined two functions/controllers, one for each route of each form submission.
4- We used `createUser()` function to extract the *username* and *email* from `req.body` and used that information to create new users.
5- We created two users and saved them to the database, one with username *"firstUser"* and the other with *"Anonymous"*

And now, it's time to create and save posts to the database. But first, let's take a look at the **PostSchema** that we've created in a previous step.

```javascript
// models/Post.js
const PostSchema = new Schema({
    title: String,   
    content: {
        type: String,
        required: true,
        trim: true,
        minlength: 5,
    },
    created_at: {
        type: Date,
        default: Date.now
    },
    author: {
        type: Schema.Types.ObjectId,
        ref: "User"
    }
});
```
The most important properties here are *author* and *content*. You can't create a post without providing an author and content.

We know that the *author* property is of type `Schema.Types.ObjectId`, which means it holds the _id for the post's writer. And since we only have two users in our database, we only have two _ids to choose from.

Let's use the `User` model and grab the _id of `firstUser` and then use that _id to create our first post.

```javascript
// contollers/postControllers.js

// get User model from ../models/User.js
const User = require('../models/User');

// get Post model from ../models/Post.js
const Post = require('../models/Post');

exports.createPost = async (req, res)=>{
    // grab the title and content
    const {title, content} = req.body;

    // fetch the first user with "firstUser" username
    const firstUser = await User.findOne({username:"firstUser"});

    // create a new instance of Post with 
    const newPost = new Post({
          title: title,
          content: content,
          author: firstUser._id
    });
    // save the post
    newPost.save()
           .then(post=>{
               res.json({msg:"newPost saved successfully", post:post})
        })
        .catch(err=>{
            console.log(err)
            res.json({msg:"An error has occured"})
        })

}
```
I think the first thing to notice about the `createPost()` function here is that we made it [async](https://javascript.info/async-await) to be able to use [await](https://javascript.info/async-await#await) so that we can easily store the values fetched from the database into variables we can use later in our code.

Like in this line:
```javascript
const firstUser = await User.findOne({username:"firstUser"});
```

Here, we used the `findOne()` method to fetch the first user in the database with the username "firstUser" and store it into the `firstUser` variable. 

In Mongoose `<Model>.fineOne()` (or any other method used to interact with the database) returns a promise, so it needs to get resolved, which means we need it to use it with `then()` and `catch()` methods.

Without `await` we would've written `createPost()` like this:
```javascript
...
  // Not async anymore
exports.createPost = (req, res)=>{
    const {title, content} = req.body;
    
    User.findOne({username:"firstUser"})
        .then(user=>{
           // 1
            const newPost = new Post({
                        title: title,
                        content: content,
                        author: user._id
                       });
           newPost.save()
                  .then(post=>{
                     res.json({msg:"newPost saved successfully", post:post})
        })
                .catch(err=>{
                   console.log(err)
                   res.json({msg:"An error has occured"})
        })
        })
        .catch(err=>{
          console.log(err)
        });
}
```
1- The thing with the second approach is that the user fetched from the database is only reachable inside the `then()` block. So in our code, we had to nest creating the `newPost` variable and saving inside `User.fineOne.then(user=>{})` because the fetched user is reachable there, not outside. 

**Note:** I am not sure if using `async/await` is the best approach of the two here, but sometimes I like to use it instead of nesting code to deeper levels.

So now, we can create new posts for "firstUser". YAY

Go to [http://localhost:3000/](http://localhost:3000/)and create a few.

Mongoose has [many methods and options](https://mongoosejs.com/docs/api/model.html) that help us interact with the database and easily create, fetch, update, or delete documents.

A few of the methods I worked with are:

1- [findOne(«selectors»)](https://mongoosejs.com/docs/api/model.html#model_Model.findOne): Fetches the first document that matches the selectors passed to it or `null` if there's no match.
```javascript
// returns the first user matched 
User.findOne({username:"Anonymous", email:"fake@gmail.com"});
```
2- [findById(«id»)](https://mongoosejs.com/docs/api/model.html#model_Model.findById): Finds the object by the passed id.
```javascript
// return the user with the id userId
const { userId } = req.params
User.findById(userId)
```

3- [find(«selectors»)](https://mongoosejs.com/docs/api/model.html#model_Model.find): Returns an array of all the documents that match the selectors or an empty array if there's no match.
```javascript
// returns an array of all the users with username "Anonymous"
User.find({username:"Anonymous"});

// returns all the users
User.find()
```

3- [findOneAndDelete(«selectors»)](https://mongoosejs.com/docs/api/model.html#model_Model.findOneAndDelete): Finds a matching document, removes it, and passes the found document (if any) to the callback.

```javascript
// finds the user with the _id userId and deletes it
const { userId } = req.params
User.findOneAndDelete({_id:userId})
```

A few of the options:
1- [limit(«Number»)](https://mongoosejs.com/docs/api/query.html#query_Query-limit): Limits returned array to the passed number.
```javascript
// returns an array of ten users with usename "Anonymous"
User.find({username:"Anonymous"})
    .limit(10)
```
2- [sort(«Object|String»)](https://mongoosejs.com/docs/api/query.html#query_Query-sort): Sets the sort order.And if an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.

```javascript
// returns an array of ten users
// sorted by id
   User.find()
       .limit(10)                              
       .sort({_id:"asc", username:"desc"})
// Or .sort('_id -username') 
```

I think that's almost all I've learned about using Moongose with Express so far. And I believe I still have a lot more to learn.

Thank you for reading

**Refrences**
[freeCodeCamp](https://www.freecodecamp.org/learn/apis-and-microservices/mongodb-and-mongoose/)
[the mongoosejs docs](https://mongoosejs.com/docs/guide.html).
[MDN](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose)
[code.tutsplus](https://code.tutsplus.com/articles/an-introduction-to-mongoose-for-mongodb-and-nodejs--cms-29527#:~:text=These%20documents%20are%20saved%20inside,via%20the%20Model's%20schema%20definition.)