Full Stack React — Part 7 (React, GraphQL, Express, MongoDB)
Episode 7: Create user resolver (evernote clone)
In the previous episode, we created our note resolvers and more… check out the last episode if you missed it → Part 6
In this episode, we’ll create our user resolver and make the connections between our notes and users.
Agenda:
- Create User resolver
- UserCreator field on notes and created notes
- Helper functions to get created notes array
Create User resolver
STEP 1: Make sure your server is up and running
STEP 2: Go inside your resolvers
folder, then go to your user.js
file. This is where you’ll write your user resolver code.
STEP 3: Let's go ahead and create the user resolver. Your user.js
file should look like this →
// user.jsconst User = require('../models/users')module.exports = {
createUser: async({userInput}) {
const user = new User({
username: userInput.username,
email: userInput.email,
password: userInput.password
}) try{
const result = await user.save()
return { ...result._doc }
}
catch(err){
throw err
} }
}
Explanation:
- We named our resolver “createUser”
- We created a user using our User Model, then store it in
const user
- In our
try block
we saved that user document in aconst result
and return that user document{ ...result._doc }
- In our
catch block
we pass in the err, and then throw err.
we are all set with creating users…
UserCreator field on notes and created notes
Now we need to head over to the notes resolver again, let’s focus on the notes resolver right now. In the notes
resolver we are currently finding all the notes in our DB and returning them, we need to add something to our return
STEP 1: In our notes resolver add userCreator
. As we discussed in previous episodes the userCreator
specifies which user created this note. It should now look like this →
notes: async () =>{try {const Notes = await Note.find({})return Notes.map(note =>{return {...note._doc, userCreator: '5d28e81606fb7981dcfd0ee8')}})}catch(err){throw err}},
For testing purposes, we added the ID of a user from our DB. Therefore, every note we get back we can now query for the userCreator
of that note as well. Which is “billy” in my DB.
However, even though we have the ID of that user, we wont get that user data back yet.
STEP 2: In our createNotes
resolver, we also need to add the userCreator
field. Which will b the same ID we used before, it should look like this now →
createNote: async ({noteInput}) =>{ const note = new Note({ title: noteInput.title, content: noteInput.content, image: noteInput.image, userCreator: '5d28e81606fb7981dcfd0ee8' --> user that created note }) let notes; try { const result = await note.save() notes = { ...result._doc } return notes }catch (err){ throw err }}
STEP 3: Now that we have the user, we need to push the notes we create to the user’s createdNotes
array. This code will do that →
createNote: async ({noteInput}) =>{const note = new Note({title: noteInput.title,content: noteInput.content,image: noteInput.image,userCreator: '5d28e81606fb7981dcfd0ee8'})let notes;try { const result = await note.save() notes = { ...result._doc } const findUser = await User.findById(5d28e81606fb7981dcfd0ee8) if(!findUser) return new Error('User not found') findUser.createdNotes.push(note) await findUser.save() return notes }catch (err){throw err}}
Explanation:
- We find the user by ID and store that document in
const findUser
- If that user does not exist we throw an error.
if(!findUser) return new Error(‘User not found’)
- If they do exist, you have access to their data (user data) along with the
createdNotes
field. Now, you can push notes to theircreatedNotes
array.findUser.createdNotes.push(note)
- After this, save the user
await findUser.save()
Overview: A note we create will have a default user attached “billy” by their ID. In order to push the note to the createdNotes
array, we need to find that user first.
Helper functions to get user and created notes
STEP 1: Still inside the notes resolver file, above the module.exports
create a method(function) called getUser
and place the following code.
const getUser = async(userid) => { try { const userID = await User.findById(userid) if(userID) return {...userID._doc} }catch(err){ throw err } }// module.exports {...}
Explanation:
- This method takes a
userid
as param - We search the DB for this user by the
userid
we pass in, then store this document inconst userID
- If we find the user, return that user data (username, email, password, createdNotes)
{...userID._doc}
STEP 2: Let’s create this getNotes
method →
const getNotes = async(noteid) =>{ try{ const notesID = await Note.find({_id: {$in: noteid}}) return notesID.map(note =>{ return {...note._doc} }) }catch(err){ throw err }}// const getUser = () => {...}// module.exports = {...}
Explanation:
- This method takes a
noteid
as param - In the
try block
, we find the note where the_id
within thecreatedNotes
array matches thenoteid
we pass in.const notesID = await Note.find({_id: {$in: noteid}})
- We then loop through this document array and return the single document of the note. →
return {…note._doc}
- Lastly, in the
catch block
we handle the error by throwing it
STEP 3: Now we need to use these helper methods where we need them. In our notes
resolver add this code.
notes: async () =>{try {const Notes = await Note.find({})return Notes.map(note =>{return {...note._doc, userCreator: getUser(note._doc.userCreator)}})}catch(err){throw err}}
Explanation:
- Instead of returning just the ID of user in
userCreator
, we will call thegetUser
method that takes in an ID(same ID, which is user “billy”) as param and actually return the user data. - This method is ONLY called if we query for the
userCreator
of a note. Catch block
will handle the error (throw err)
STEP 4: Let’s do the same thing in the getUser
method.
const getUser = async(userid) =>{try {const userID = await User.findById(userid)if(userID) return {...userID._doc, createdNotes: getNotes(userID._doc.createdNotes)}}catch(err){throw err}}
Explanation:
- Since we want to query for the created notes associated with this user we must get these notes with the help from our
getNotes
method - we pass in the userID createdNotes array so that our
getNotes
can find the_id
that matches a id in the array you passed in.
Be sure to test these queries out to make sure its working
Ex: When you query for notes, see if you can also query for userCreator
you should now be able to get the user data back and you can query for their createdNotes
if you want.
{
notes{
_id,
title,
userCreator{
username,
} }}
If anything goes wrong try starting from scratch and empty out your collections (notes and users) and create a new user and replace the following fields with the userID. Then create note with this user and try querying again.
createNote: async ({noteInput}) =>{const note = new Note({title: noteInput.title,content: noteInput.content,image: noteInput.image,userCreator: 'userID you just created'})let notes;try {const result = await note.save()notes = {...result._doc}const findUser = await User.findById('userID you just created')if(!findUser) return new Error('User not found')findUser.createdNotes.push(note)await findUser.save()return notes}catch (err){throw err}}
That is all for this episode, if you guys have any questions please feel free to ask me :) I hope you guys enjoy…more to come
If you would like to watch the video, you can check it out here → Create user resolver and more