Mongoose Using Enum with Express - node.js

The user schemas has the key, bookmarks, where the user can mark discussions and responses as bookmarked, but I'm not sure how to specify that in my schema.
const userSchema = new Schema({
...
bookmarks: [ {
type: Schema.Types.ObjectId,
ref: 'Discussion' // <-- Discussion or Response dynamically
} ],
});
I looked into Mongoose Enum's but I was unable to determine that in the backend which one it was.
How do I:
Set enum ref in Schema
Make request via Redux action creator and sending the id
Allow backend to determine if it's Discussion or Response
How do I later access it through Express/Mongoose
The way I'm expecting this to work:
User clicks the bookmark button on either a Discussion Card or Response Card
Redux fires an action creator to make a POST request to /api/bookmark/:itemId
Express figures out whether it's Discussion or Response and unshifts item to bookmarks key
When user makes a GET request to get all bookmarks, Mongoose populates the bookmarks array and sends back the result

Related

Does it matter if you use POST or PUT when updating a Mongoose Subdocument in MongoDB?

Does it matter if you use POST or PUT when updating a Mongoose subdocument in MongoDB? Originally I was using PUT to update, but it wasn't working with an API I added in later, so I changed it to POST and it appears to work for updating the subdocument. So does it really matter which you use with MongoDB? I'm guessing PUT has plenty of uses in other cases.
Schemas for reference:
const hikeSessionSchema = new mongoose.Schema({
hike_name: {type: String, required: true}
})
const hikerSchema = new mongoose.Schema({
email: {type: String, required: true},
password: {type: String, required: true},
log: [hikeSessionSchema]
})
1
Either one should be possible.
Zooming out, let's think about why this is the case by thinking about what happens at a high level.
A client sends an HTTP request to a server.
The server receives the request.
The server parses the request (eg. such that req.method is POST).
The server decides what code to execute (eg. app.post('/foo/bar', handler)).
The server executes that code (eg. handler()).
Roughly. The big point here is that in step 4, it is the server that decides what to do. The request could be DELETE. It doesn't matter. The server can decide that when it sees a DELETE request, it's going to create a record. Now, that is probably a bad idea. My point is just that it is possible.
With that said, let's think about why it is only working with POST but not PUT. You'll have to look through your server code and check out how the routing is done (perhaps with Express?). There is going to be some routing logic that is looking for a POST request. You can change it to look for PUT instead if you would like.
To be clear, the answer will lie in your server's routing logic. It actually has nothing to do with Mongoose. Mongoose lives in step five of my outline above, whereas the answer to your question lives in step four.
2
Let's ask the question of whether it should be PUT, POST, or maybe something else.
POST is for creating records.
PUT is for replacing entire records.
PATCH is another option available for updating a portion of an existing record.
So if you have a User record with a username, email and password, if you are sending over { username: "johndoe", email: "johndoe#example.com", password: "020392" } as the request payload and replacing the existing record with those values, then that would be a PUT request. But if you only want to change, let's say the email, then you could send something like { email: "johndoe#example.com" } to the server and only update that email field with Mongoose, and use a PATCH request for that. Check out Use of PUT vs PATCH methods in REST API real life scenarios for more information on PUT vs PATCH.
Actually no difference between POST and PUT for mongoose. But in web API those method have different.
Im rest API POST for use add something for example add new user in web server and PUT use for update something like update user info
But actually no difference between POST and PUT in http, It's just standard and you can add ad update with POST
If you're interesting about that topic you can read below document:
https://www.restapitutorial.com/lessons/httpmethods.html

How to populate objects in mongoose

What am i trying to do is a single todo app where you can create user and log in with that user.Every user can CRUD for single todo and can fetch all of the todos that are linked to that particular user.
this is the schema for the userSchema
const userSchema = new Schema({
firstName:{type:String,trim:true},
lastName:{type:String,trim:true},
userName:{type:String,required:true,unique:true,sparse:true,trim:true},
email:{type:String,required:true,unique:true,sparse:true,trim:true},
phoneNumber:{type:String,unique:true,sparse:true,required:true},
hash:{type:String,required:true}
})
and i have todoSchema
author:{type: Schema.Types.ObjectId},
title:{type:String, required:true, trim:true},
context:{type:String, trim:true,},
isFinished:{type:Boolean,required:true,default: false},
finishedAt:{type:Date}
Also i have login system that works with JWT,My question is how can i save todo with the id of the user that is currently logged in..And also how can i fetch all todos that are linked to the user that is currently logged in
I dont want todos to be stored in userSchema as array,rather as different schema where you can do CRUD for each todo
-I was reading something called populate that comes with mongoose but i dont know how to implement that
--It will be very nice if you can give me some ideas how to do that..I don't need full implementation..Thank you
-If you need more of the code here it is https://github.com/jkuzmanovik/todoApi
Once the user is logged in ( I guess you are using passport ) passport creates req.user which can be. req.user will contain all the details given in the user schema while creating passport plugin.
This can be used to populate your toDo schema like follows:
in the get request you do
toDo.find({})
.populate('author')
...
But if your goal is to find all toDos by the user you can do as follows
toDo.find({author:req.user._id})
This can be done only after authentication.
This will get you all the todos by the user.
PS: Once you populate only the author field will be replaced (not the proper word but understandable) by the user object itself, it does not help in filtering. Mongoose population should be used meticulously as it is database resource hungry and will reduce the server performance.
About JWT, whenever you make a req you need to pass the JWT to the server (by URL, authorization header etc.). There is a method called extract which will extract the user from the JWT token and thus authentication is possible.
More about that read documentation on passport-jwt and jsonwebtoken.

Getting data for user based on JWT in Node/Express

This question is half about my code specifically, and half about the high-level view of actually getting data for a particular user from a node API.
So I have user signup/signin all working fine, and lets say I have a one-to-many mapping between Users and Widgets, so each User can create and delete Widgets from his or her profile page.
So here are my database models:
var User = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
hash: String,
salt: String
widgets : [{ type: Schema.Types.ObjectId,
ref: 'widget'
}],
});
var Widget = new mongoose.Schema({
name : String,
type : String,
description : String,
});
In the user login process, I generate a JWT and use that to save an authorization header on the front-end.
Now my question is two-fold. 1) How do I correctly save widgets so that they are associated with the currently logged in User? and 2) How do I get all widgets associated with a user?
My initial thoughts are something like this:
app.get('api/widgets', function(req, res, next){
// decode authorization header to get user email
// run database query to return all widgets associated with user email
});
app.post('api/widgets', function(req, res, next){
// decode authorization header to get user email
// create widget and update user with widget ID
});
Is this the correct idea? And if so, how would I go about decoding the authorization header to get the user's email? Do I need to go through this same process for every object associated with the User? Or is there a faster and more convenient way to do this in Node/Express?
Is this the correct idea?
In my opinion, yes, that is correct.
And if so, how would I go about decoding the authorization header to get the user's email?
If you're using jsonwebtoken package, there's a verify method that decodes the token. You can even store multiple values in a single token, like e-mail and name. verify will decode the token into an object with both properties.
Do I need to go through this same process for every object associated with the User? Or is there a faster and more convenient way to do this in Node/Express?
Loading those objects on every request is probably the most common method. If you find that this loading process is slowing down your application, you can cache it using node-cache or Redis (recommended when you have a distributed application cluster).
I also suggest that, instead of decoding the user's token into an email on every route, it's common to use a catch all route that decodes the token and store in the locals. DRY!
app.use(function (req, res, next) {
var token = req.signedCookies.token
res.locals.user = jwt.verify(token, 'my-secret')
next()
})

Authentication with passport. Can I trust that req.user is indeed the logged in user?

I'm using passport to authenticate users at my site. Users can register orders, which have and foreignKey (ObjectId) to the User object.
Example-objects (written as mongoose schemas):
var orderSchema = new mongoose.Schema({
...
address: String,
_userID: {type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User'}
});
var userSchema = new mongoose.Schema({
email: String,
});
Mongoose will create the primary key for each object.
My question is; is it enough to check if req.user._id === order._userID? Or can the req.user object be tampered with? Can I trust that req.user._id is the id of the logged in user?
I've found a couple of good resources, but it's not exactly what I'm asking of.
http://toon.io/articles/understanding-passportjs-authentication-flow/
http://passportjs.org/guide/authenticate/
So the question:
can the req.user object be tampered with?
Is difficult to answer, since you could have code within your application that will have access to your request object, and within it, modify the user. It's important to understand what code you have running within the flow of each request for anyone really, but especially those concerned about the security of their application. With that said, I can at least point you to where in the code this is established, and you can trace it with a debugger to assure yourself of the flow.
As you've mentioned, the passport documentation discusses authentication configuration options in their guide, and by default will process "logging in" the user when your strategy dictates successful authentication. You can provide a custom callback (mentioned in the referenced documentation above) to process this as well. In the end, it's important that req.logIn is called (which is done by default without any custom callbacks provided). Here's a link to the source. (Passport extends the request object via this code to provide helper functions which it later uses.)
The specific line you maybe interested in is here, which assigns to the req object the property user with a value of the authenticated user:
this[property] = user;
From there on, you have access to the logged in user under req.user, and their ID under req.user.id. Again note that this logIn function should only be called when the passport strategy states that successful authentication has occurred. But in this way, passport has provided you with a way of easily authenticating the user, and then getting access to this user via the request object.

Saving a user's favorites

I am trying to associate a user authenticated with passport.js with a backbone.js collection or an array of ids (I don't which solution is the best) and save this in mongoDB.
I use node.js on server side.
Is it possible?
(for instance saving a user's favorites).
You can define a User schema like this:
var User = new Schema({
favorites: [{
whatHaveYou: String,
}]
})
Now, with using passport.js, after you have authenticating the user with this schema, you will be able to access the favorites with: req.user.favorites.
I suggest you go throw this demo project on github for setting up a node-express-mongoose project with passportjs if you have any more questions: https://github.com/madhums/node-express-mongoose-demo, this helped me a lot.

Resources