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"
}
});
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"})
})
}
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"});
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)
});
}
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"});
2- findById(«id»): Finds the object by the passed id.
// return the user with the id userId
const { userId } = req.params
User.findById(userId)
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()
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})
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)
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')
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)