DEV Community

Hajar | هاجر
Hajar | هاجر

Posted on

Extra Step: Writing Posts

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.

// 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"
    }
});
Enter fullscreen mode Exit fullscreen mode

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.

// 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"})
        })

}
Enter fullscreen mode Exit fullscreen mode

I think the first thing to notice about the createPost() function here is that we made it async to be able to use 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:

const firstUser = await User.findOne({username:"firstUser"});
Enter fullscreen mode Exit fullscreen mode

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:

...
  // 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)
        });
}
Enter fullscreen mode Exit fullscreen mode

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/and create a few.

Mongoose has many methods and options 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»): Fetches the first document that matches the selectors passed to it or null if there's no match.

// returns the first user matched 
User.findOne({username:"Anonymous", email:"fake@gmail.com"});
Enter fullscreen mode Exit fullscreen mode

2- findById(«id»): Finds the object by the passed id.

// return the user with the id userId
const { userId } = req.params
User.findById(userId)
Enter fullscreen mode Exit fullscreen mode

3- find(«selectors»): Returns an array of all the documents that match the selectors or an empty array if there's no match.

// returns an array of all the users with username "Anonymous"
User.find({username:"Anonymous"});

// returns all the users
User.find()
Enter fullscreen mode Exit fullscreen mode

3- findOneAndDelete(«selectors»): Finds a matching document, removes it, and passes the found document (if any) to the callback.

// finds the user with the _id userId and deletes it
const { userId } = req.params
User.findOneAndDelete({_id:userId})
Enter fullscreen mode Exit fullscreen mode

A few of the options:
1- limit(«Number»): Limits returned array to the passed number.

// returns an array of ten users with usename "Anonymous"
User.find({username:"Anonymous"})
    .limit(10)
Enter fullscreen mode Exit fullscreen mode

2- sort(«Object|String»): Sets the sort order.And if an object is passed, values allowed are asc, desc, ascending, descending, 1, and -1.

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

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
the mongoosejs docs.
MDN
code.tutsplus

Top comments (0)