How to populate objects in mongoose - node.js

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.

Related

Creating USERs table in Express

I'm pretty new to Express and NodeJS (less than a week) and I have a noobish question.
Background
I have made a REST API from a tutorial using Express and Passport for Authentication (which is just a basic auth with username and password and I get a token back in my requests).
I want to have something like Instagram or Facebook in which users have some information (name, birthdate etc.) and they can post texts.
Model/Account.js
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
import passportLocalMongoose from 'passport-local-mongoose';
let Account = new Schema({
email: String,
password: String
});
Account.plugin(passportLocalMongoose);
module.exports = mongoose.model('Account', Account);
Problem
I don't know if I should add fields to the Model that I created for Authentication (which only has email and password) or I should create a separate Table, like USERS in my Database (I know it's a JSON file and not a database but don't know the technical name).
Please if any, give some hints here or keywords so that I can google myself.
Thanks a lot in advance :)
i think you should add the field is existing model that you create for Authentication because if you made another model you have to repeat the data in your case it is email and password which does not make any sense and it also cause problems and confusion to fetch or manage data in both tables so i prefer you to insert the field in same model that you create for Authentication
I would be inclined to reuse your accounts mongoose model for your user model.
Reason being is that you already have captured email and password which is what you would usually store in a user model.
You can add your additional fields to what you already have.
I think you should consider a general schema for account authentication model and use the schema in all authentication cases. I prefer add other fields to exist model.

Mongoose Using Enum with Express

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

Using PassportJS LocalStrategy in Node.js and trying to create a User object

Inside the LocalStrategy function I am trying to create a new user that I can pass-back with:
var newUser = new User();
and I am getting this error
TypeError: object is not a function
I can't seem to find the what has the definition for User()
Any ideas?
passport has no definition for User, per se. It sounds to me as if you might want to make use of a schema or similar kind of model.
For example, if your back-end is based on MongoDB, the mongoose project offers schema definitions, amongst other things. With mongoose you can set up a User object definition (i.e. schema), and then make use of it like so:
var user = app.db.models.User.findOne( {...})

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