Getting user details in other schema[mongoose] - angularjs

I'm getting my hands on mean stack development. I'm kinda stuck where my requirement is to get posted by functionality. I'm trying to build a simple classified ads app where a user adds/updates/deletes a classified. I'm able to do all of these but now I need to display the name of that particular user on that add who is logged in. I've researched online but couldn't get the solution.
My schema
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true, lowercase: true },
phone: { type: Number, min: 10, unique: true },
hash: String,
salt: String
});
var ClassifiedSchema = new Schema({
title: { type: String, required: true, unique: true },
description: { type: String, required: true, },
price: { type: Number, required: true },
created: { type: Date, default: Date.now },
updated: { type: Date, default: null },
contact: {
name: String,
phone: Number,
email: String
},
image: String,
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
});
My route
router.route('/classifieds')
.post(function(req, res) {
var classified = new Classified(req.body);
classified.save(function(err, classified) {
if (err)
res.send(err);
res.json(classified);
});
})
.get(function(req, res) {
Classified.find(function(err, classifieds) {
if (err)
res.send(err);
res.json(classifieds);
});
});
router.route('/register')
.post(function(req, res) {
if (!req.body.username || !req.body.password || !req.body.email || !req.body.firstName || !req.body.lastName) {
return res.status(400).json({message: 'Please fill all the fields!'});
};
var user = new User(req.body);
user.setPassword(req.body.password);
user.save(function(err, user) {
if (err)
res.send(err);
res.json({ token: user.generateJWT()});
});
});
router.route('/login')
.post(function(req, res) {
if (!req.body.username || !req.body.password) {
return res.status(400).json({ message: 'Please fill all the fields!' });
};
passport.authenticate('local', function(err, user, info) {
if (err)
res.send(err);
if (user) {
return res.json({ token: user.generateJWT() });
} else {
return res.status(401).json(info);
};
})(req, res);
});
I want to know how do I get the username while posting the classified? I'm aware of the populate function but I've tried it and it doesn't seem to work.
Update
I've added my register and login route to show you the use of passport.

If you have an authentication system like passport which sets req.user to current logged in user, then:
.get(function(req, res) {
Classified.find({user: req.user},function(err, classifieds) {
if (err)
res.send(err);
res.json(classifieds);
});
});

Related

MongoServerError: E11000 duplicate key error collection with no collection

Why I'm getting this error!!
GOOGLE USER: null
/Users//my-blog/api/node_modules/mongodb/lib/operations/insert.js:53
return callback(new error_1.MongoServerError(res.writeErrors[0]));
^
MongoServerError: E11000 duplicate key error collection: blog.users
index: email_1 dup key: { email: "" }
I dropped the whole collection in Mongodb and when I tried again it gave me the same error but the data stored in MongoDB collection, the problem is with the error it stops the whole app from running. I don't know where I went wrong or what I'm missing.
Auth.js Code:
router.get("/google", passport.authenticate("google", {
scope: ["profile", "email"] }));
router.get("/auth/google/callback", passport.authenticate("google", {
successRedirect: "http://localhost:3000/",
failureRedirect: "/googleLogin/failed"
}));
router.get("/googleLogin/success", async (req, res)=>{
if(req.user){
const user = await User.findOne({provider_id: req.user.id,
provider: req.user.provider})
if(user){
res.status(200).json({
success: true,
message: "success",
user: user
})
console.log("GOOGLE USER IS: " + user)
}else{
const checkUserEmail = await User.findOne({email: req.user.email})
if(checkUserEmail){
res.status(401).json({
success: false,
message: "User already Exist with this email id",
})
}else{
const user = await User.create({
username: req.user.name.givenName+ "_" +req.user.name.familyName,
firstName: req.user.name.givenName,
lastName: req.user.name.familyName,
email: req.user.emails[0].value,
provider: req.user.provider,
provider_id: req.user.id,
// profilePic: req.user.photos?.[0]?.value,
});
res.status(200).json({
success: true,
message: "success",
user: user
})
}
}
console.log("GOOGLE USER: ", user);
}
})
router.get("/googleLogin/failed", (req, res)=>{
if(req.user){
res.status(401).json({
success: false,
message: "failure",
})
}
})
I THINK the code keeps running nonstop ! thats why it giving me the error even so the collection is empty, it sign up the user then it sign up again non stop. I think that it should be a done() in the code but I didn't know how to fix it.
Passport.js Setup:
passport.use(new GoogleStrategy({
clientID: process.env.REACT_APP_GOOGLE_CLIENT_ID,
clientSecret: process.env.REACT_APP_GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
passReqToCallback: true,
scope: ["profile", "email"],
},
function(request, accessToken, refreshToken, profile, done){
console.log(profile.emails[0].value);
console.log(profile.photos[0].value);
return done(null, profile)
}
));
passport.serializeUser((user, done)=>{
done(null, user)
})
passport.deserializeUser((user, done)=>{
done(null, user)
})
Here is my User Schema: User.js
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: false,
/* Can't create a user with the same username */
unique: true,
minlength: 3,
maxlength: 30,
},
firstName: {
type: String,
required: false,
unique: false,
maxlength: 20,
},
lastName: {
type: String,
required: false,
unique: false,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
},
repeatPassword: {
type: String,
},
profilePic: {
type: String,
default: "",
},
birthday: {
type: String,
required: false,
unique: false,
},
country: {
type: String,
required: false,
unique: false,
},
googleId: {
type: String
},
provider: {
type: String,
default: "email"
},
provider_id: {
type: String,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);

Mongoose - Cannot Update update deeply nested Objects

var ItemSchema = new Schema({
item: {type: String, required: false},
ts: {type: String, required: true},
selldate: {type: Number, required: false},
replaced: [ReplaceSchema]
});
var ProductSchema = new Schema({
title: {type: String, required: true, trim: true}, //name of the products
artNo: {type: Number, required: true},
catId: {type: String, required: true},
productType: {type: String, required: true}, //physical, textbased or downloadable product | can be 'dl', 'txt', 'phy'
tid: {type: String, required: false}, //only needed for physical products for providing a tid
minItems: {type: Number, required: true},
ts: {type: Number, required: true}, // when was the product online
buyCount: {type: Number, required: true}, // baught how many times
description: {type: String}, //more about the product
price: {type: Number, required: true}, // how much?
discounts: [DiscountSchema], // discount objects
items: [ItemSchema],
images: [], // fullsize images of the product
thumbnails: [], // small preview images of the product
// isPublic: {type: Boolean, required: true}, // if product should be published or not
itemCount: {type: Number, required: false} // how many items exists on the product
});
var CategorySchema = new Schema({
name: {type: String, required: true},
ts: {type: Number, required: true},
products: [ProductSchema]
});
So you see its: Category -> products[] -> items[]
I want to update the Objects in items array in the database and set (at this time undefined field "selldate".
My code snippet for this looks like this:
Category.getProductOfCategory(productId, function(err, boughtProduct) {
if (err) {
res.send({
status: false,
data: err
})
} else {
// console.log('BoughtProduct: ', boughtProduct.products[0])
var bought = boughtProduct.products[0];
// console.log('theItem: ', bought.items.id(item._id));
bought.items.id(item._id).selldate = Date.now();
bought.save(function(err, results) {
if (err) {
res.send({
status: false,
data: err
})
} else {
// i is increased because we need it on line 5
// console.log('itemerr', err)
console.log('saved', results);
j++;
// the next() function is called when you
// want to move to the next item in the array
next();
}
});
}
});
But nothing is happening in the database. Im getting No errors but "results" is just undefined.
Can you please help me?
Update:
I have a solution BUT it works only on executing it once.. after that, its nothing happening again...
The Code:
Category.findById(catId, function (err, data) {
if (err) console.log(err);
data.products.id(productId).items.id(item._id).selldate = Date.now();
data.save(function (err, result) {
if (err) console.log(err);
j++;
next();
});
});
i have posted a sample program containing documents & sub-documents.
Kindly check this and let me know if you need additional information
Schema
const PostSchema = new Schema({
title : String
});
const HomeSchema = new Schema({
"name" : {
type : String,
required : true
},
"city" : {
type : String,
required : true
},
post : [PostSchema]
});
To Save document and subdocument
const cat = new HomeModel({
name: "tiger",
city : "africa",
post : [{
"title" : "tiger post"
}]
});
cat.save((user) => {
console.log("saved");
console.log(user);
})
.catch((err)=>{
console.log("err");
console.log(err);
});
To update document
HomeModel.update({name : "tiger"},{city : "china123"})
.then((home)=>{
console.log("updated");
console.log(home);
})
.catch((error) => {
console.log("error");
console.log(error);
});
To add new subdocument
HomeModel.findOne({name : "tiger"})
.then((home) => {
console.log("findone")
console.log(home);
home.post.push({"title" : "monkey"});
home.save();
})
.catch((err)=>{
console.log("error");
});
To update existing subdocument
method:1
HomeModel.findOne({name : "tiger"})
.then((home) => {
console.log("findone")
const tes=home.post.id("5a3fe65546c99208b8cc75b1");
tes.set({"title" : "it workssdfg"});
home.save();
})
.catch((err)=>{
console.log("error");
});
To find parent document using sub-document id
HomeModel.findOne({"post._id" : "5a3fe65546c99208b8cc75b1"})
.then((home) => {
console.log("findone")
console.log(home);
})
.catch((err)=>{
console.log("error");
});

Mongoose: 'Cast to embedded failed for value at path. Cannot use 'in' operator to search for '_id'

I'm having some trouble trying to save an array inside an array of objects.
I'm getting the following response from the server:
{ [CastError: Cast to embedded failed for value "\'maxbeds: 4\'" at path "saved_searches"]
message: 'Cast to embedded failed for value "\\\'maxbeds: 4\\\'" at path "saved_searches"',
name: 'CastError',
kind: 'embedded',
value: '\'maxbeds: 4\'',
path: 'saved_searches',
reason: [TypeError: Cannot use 'in' operator to search for '_id' in maxbeds: 4] }
Here's my Schema:
var mongoose = require('mongoose'),
rfr = require('rfr'),
passwordHelper = rfr('server/helpers/password.js'),
Schema = mongoose.Schema,
_ = require('lodash');
/*
*
* Creating UserSchema for MongoDB
*
*/
var UserSchema = new Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
select: false
},
name: {
type: String,
required: true
},
passwordSalt: {
type: String,
required: true,
select: false
},
saved_houses: [{
mlsId: {
type: String
},
addressFull: {
type: String
},
bedrooms: {
type: Number
},
listPrice: {
type: Number
},
bathrooms: {
type: Number
},
sqft: {
type: Number
},
createdAt: {
type: Date,
default: Date.now
}
}],
saved_searches: [{
search_name: {
type: String
},
filters: {
type: [Schema.Types.Mixed]
},
createdAt: {
type: Date,
default: Date.now
}
}],
active: {
type: Boolean,
default: true
},
createdAt: {
type: Date,
default: Date.now
}
});
// compile User model
module.exports = mongoose.model('User', UserSchema);
The problem, I believe is the filters array that live inside an object inside the saved_searches array
Now, in my router I do the following:
var express = require('express'),
savedDataRouter = express.Router(),
mongoose = require('mongoose'),
rfr = require('rfr'),
s = rfr('server/routes/config/jwt_config.js'),
User = rfr('server/models/User.js'),
jwt = require('jsonwebtoken');
savedDataRouter.post('/searches', function (req, res) {
if (mongoose.Types.ObjectId.isValid(req.body.userId)) {
User.findByIdAndUpdate({
_id: req.body.userId
}, {
$push: {
saved_searches: {
search_name: req.body.search_name,
$each: req.body.filters
}
},
}, {
new: true
},
function (err, doc) {
if (err || !doc) {
console.log(err);
res.json({
status: 400,
message: "Unable to save search." + err
});
} else {
return res.json(doc);
}
});
} else {
return res.status(404).json({
message: "Unable to find user"
});
}
});
If I log the request body coming from the client I get the following:
//console.log(req.body)
{ search_name: 'Sarasota',
filters: [ 'minbaths: 1', 'maxbaths: 3', 'minbeds: 2', 'maxbeds: 4' ],
userId: '583359409a1e0167d1a3a2b3' }
I've tried all the things I've seen in Stack Overflow and other online resources with no luck. What am I doing wrong?
Edit
Added module dependencies to my UserSchema and SavedDataRouter
try this
User.findByIdAndUpdate({
_id: req.body.userId
}, {
$push: {
saved_searches: {
search_name: req.body.search_name,
filters: req.body.filters
}
},
}, {
new: true
},
function (err, doc) {
if (err || !doc) {
console.log(err);
res.json({
status: 400,
message: "Unable to save search." + err
});
} else {
return res.json(doc);
}
});

User registeration as inactive and activation via OTP

Following are the steps for authentication flow:
User does the registeration by entering his details and he will be
sent an OTP to his mail.
At this time user details stored to
mongoDB.
Usually after validation of OTP, a user can login to
application. But in my case before validating OTP, user can login to
application.
How to solve this please help me. Some of my code shown below.
model.js
var UserSchema = new Schema({
name: String,
email: {type: String, required: true, select: true},
mobile: {type: String, required: true, select: true},
password: {type: String, required: true, select: true},
});
controller.js
vm.submitPost = function(userData){
$http({
url: 'http://192.168.2.8:7200/api/pages/auth/register',
method: 'POST',
data: userData
}).then(function(res) {
if(res.data.success){
$location.path('/pages/auth/otp');
} else {
alert('Please fill all credentials');
}
}, function(error) {
alert(error.data);
});
};
node.js
router.post('/pages/auth/register',function(req, res, next){
var user = new User({
name: req.body.username,
email: req.body.email,
password: req.body.password,
mobile: req.body.mobile,
});
var secret = "mysecretkey";
var code = otp.generate(secret);
var insertOtp = function(db, callback) {
db.collection('otp').createIndex( { "createdAt": 1 }, { expireAfterSeconds: 10 } );
db.collection('otp').insertOne( {
"createdAt": new Date(),
"generatedOtp": code,
"logEvent": 2,
"logMessage": "Success!"
}, function(err, result) {
assert.equal(err, null);
callback(result);
});
};
MongoClient.connect(config.database, function(err, db) {
assert.equal(null, err);
insertOtp(db, function(err,docs) {
db.close();
});
});
var mailOptions={
to : req.body.email,
subject : 'OTP',
text : "Your One-Time Password is "+code
}
transport.sendMail(mailOptions, function(error, response){
if(error){
console.log(error);
res.end("error");
}else{
res.end("sent");
}
});
user.save(function(err){
if(err){
res.send(err);
return;
}
res.json({
success:true,
message: 'User has been created!'
});
});
});
add active attribute to your schema with default value false when user has validated through OTP, then set this attribute to true and allow user to login if this attribute is true.
var UserSchema = new Schema({
name: String,
email: {type: String, required: true, select: true},
mobile: {type: String, required: true, select: true},
password: {type: String, required: true, select: true},
active:{ type: 'Boolean',
default: false}
});

How to push to an array in mongoose

I have this code:
router.post('/setsuggestions', function(req, res, next){
if(!req.body.username || !req.body.challengessuggestions){
return res.status(400).json({message: challengessuggestions});
}
var query = { username: req.body.username };
/*User.findOneAndUpdate(query, { challengessuggestions: req.body.challengessuggestions }, callback = function(response){
res.json(response);
});*/
/*
User.findOneAndUpdate(
query,
{$push: {"challengessuggestions": {$oid: req.body.challengessuggestions}}},
callback = function(response) {
res.json(response);
}
);*/
User.findOneAndUpdate(
query,
{$push: {challengessuggestions: req.body.challengessuggestions}},
{safe: true, upsert: true},
function(err, model) {
res.json(err);
}
);
});
When I postman like this:
I get the following error:
{ "name": "MongoError", "message": "exception: The field
'challengessuggestions' must be an array but is of type OID in
document {_id: ObjectId('56263b910d1a2f1f0077ffae')}", "errmsg":
"exception: The field 'challengessuggestions' must be an array but is
of type OID in document {_id: ObjectId('56263b910d1a2f1f0077ffae')}",
"code": 16837, "ok": 0 }
This is the schema definition of AppUser:
var UserSchema = new mongoose.Schema({
username: { type: String, lowercase: true, unique: true },
firstname: { type: String},
lastname: { type: String},
difficulty: { type: String},
isstudent: { type: Boolean },
haschildren: { type: Boolean},
gender: { type: String },
email: { type: String, unique: true},
birthdate: String,
isdoingchallenges: { type: Boolean },
challengescompleted: [{ type: ObjectId, ref: 'Challenge' }],
currentchallenge: { type: ObjectId, ref: 'Challenge' },
challengessuggestions: [{ type: ObjectId, ref: 'Challenge' }],
hash: String,
salt: String
});
This is the schema definiton of challenge:
var Challengeschema = new mongoose.Schema({
name: { type: String, initial: true, required: true, index: true },
image: { type: Array },
difficulty: { type: String },
studentfriendly: { type: Boolean },
childfriendly: { type: Boolean },
description: { type: String }
});
I'm sending this in the function that calls the api:
Object {_id: "5631423f8c5ba50300f2b4f6", difficulty: "medium", name:
"Probeer 1 van onze recepten.", __v: 0, childfriendly: true…}
This gives me following error:
D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\lib\schema\obj
ectid.js:134
throw new CastError('ObjectId', value, this.path);
^ Error
at MongooseError.CastError (D:\Stijn\Documenten\EVA-project-Groep-6\Api\node
_modules\mongoose\lib\error\cast.js:18:16)
at ObjectId.cast (D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\m
ongoose\lib\schema\objectid.js:134:13)
at Array.MongooseArray.mixin._cast (D:\Stijn\Documenten\EVA-project-Groep-6\
Api\node_modules\mongoose\lib\types\array.js:124:32)
at Array.MongooseArray.mixin._mapCast (D:\Stijn\Documenten\EVA-project-Groep
-6\Api\node_modules\mongoose\lib\types\array.js:295:17)
at Object.map (native)
at Array.MongooseArray.mixin.push (D:\Stijn\Documenten\EVA-project-Groep-6\A
pi\node_modules\mongoose\lib\types\array.js:308:25)
at Query. (D:\Stijn\Documenten\EVA-project-Groep-6\Api\routes\ind ex.js:144:44)
at D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\node_mo
dules\kareem\index.js:177:19
at D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\node_mo
dules\kareem\index.js:109:16
at doNTCallback0 (node.js:408:9)
at process._tickCallback (node.js:337:13) 29 Oct 22:05:38 - [nodemon] app crashed - waiting for file changes before starti ng...
How do I solve this?
Query the User user using findOne() first and use the first found document that's passed to the callback to save the embedded documents with:
router.post('/setsuggestions', function(req, res, next){
if(!req.body.username || !req.body.challengessuggestions){
return res.status(400).json({message: challengessuggestions});
}
var query = { username: req.body.username };
User.findOne(query, function (err, user){
if (err) //throw ...
if (user) {
if (user.challengessuggestions && user.challengessuggestions.length) {
user.challengessuggestions.push(req.body.challengessuggestions);
}
else {
user.challengessuggestions = [req.body.challengessuggestions];
}
// save changes
user.save(function (err) {
if (!err) {
// done ...
}
});
}
});
);

Resources