This question already has answers here:
How can I display a JavaScript object?
(40 answers)
Closed 5 years ago.
Using passport with nodejs and mongo/mongoose.
I store attendance records in a collection which use req.user.id as a lookup to tie the attendance records to a registered user. The key field is called "userId."
In attempting a join, I learned that the _id in the users collection is not of type string. I've been trying to work around this for quite a bit. My latest is to try to save the attendance records after converting the req.user.id to ObjectId(). Still, no luck. It looks like the userId is still saving as string. How can I get this Join to work?
router.post('/', ensureAuthenticated, function(req, res){
var query = { userId: req.user.id };
var update = {
userId: new ObjectId(req.user.id), // This is where I need to save
response: req.body.inOrOut,
notes: req.body.notes
};
// Upsert
var options = { upsert: true };
// Use mongoose to save via upsert.
RSVP.findOneAndUpdate( query, update, options, function( err, doc ) {
if ( err ) throw err;
});
Here is the join:
RSVP.aggregate([{
$lookup: {
from: "users", // collection name in db
localField: "userId",
foreignField: "_id",
as: "user"
}
}
]).exec( (err, rsvpList) => {
if (err) throw err;
console.log(rsvpList);
});
EDIT:
I just realized my mongoose schema for rsvps still had userId as string. I changed it as follows:
let mongoose = require('mongoose');
//let ObjectId = require('mongodb').ObjectId;
// RSVP Schema
var RSVPSchema = mongoose.Schema({
userId: {
//type: String,
type: mongoose.Schema.Types.ObjectId,
index:true
},
response: {
type: String
},
notes: {
type: String
},
});
var RSVP = module.exports = mongoose.model('RSVP', RSVPSchema);
My console.log:
console.log('rsvp: ' + rsvpList[0].user.toString());
It shows [Object object]. I can't tell by this whether my join has worked. How can I test rsvpList[0].user to see if it contains the joined user?
I was close. It should have been:
console.log('rsvp: ' + rsvpList[0].user[0].name);
Related
I'm currently building a Node backend with MongoDB / Mongoose and I seem to be having some problem with tying my data together. Specifically, I wish for all users to be able to submit a form (question form) which will then be added to the "questions" collection. In addition to being added to the questions collection, I also need to store a reference to all of the questions a user has answer directly inside of the user object.
Below you can check out my code. Whenever I make a POST requestion to /questions, it spits out this error. I should note that it successfully adds documents into the questions collection, and each question contains the ID of the user who created it, but the main problem is the user's questions array is not getting updated to include an ID value of submitted questions.
Models/User.js
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs');
const UserSchema = new Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
password: {
type: String,
required: true
},
profile: {
firstName: { type: String },
lastName: { type: String }
},
questions: [
{
type: Schema.Types.ObjectId,
ref: 'Question'
}
],
role: {
type: String,
enum: ['Member', 'Client', 'Owner', 'Admin'],
default: 'Member'
},
resetPasswordToken: { type: String },
resetPasswordExpires: { type: Date }
},
{
timestamps: true
});
/** Pre-save of user to database,
hash password if password is modified or new
*/
module.exports = mongoose.model('User', UserSchema);
Models/Question.js
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
// Schema defines how questions will be stored in MongoDB
const QuestionSchema = new Schema({
questionString: String,
answer: Boolean,
_createdBy : [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
],
},{
//user timestamps to save date created as .createdAt
timestamps: true
});
module.exports = mongoose.model('Question', QuestionSchema);
Controller/QuestionController.js
const jwt = require('jsonwebtoken'),
crypto = require('crypto'),
Question = require('../models/question'),
User = require('../models/user'),
config = require('../config/main');
function setQuestionInfo(request) {
return {
_id: request._id,
questionString: request.questionString,
answer: request.answer,
user: request.user
}
}
exports.addQuestion = function(req, res, next) {
User.findById(req.user.id, (err, user) => {
if (err) throw new Error(err);
// We create an object containing the data from our post request
const newQuestion = {
questionString: req.body.questionString,
answer: req.body.answer,
// in the author field we add our current user id as a reference
_createdBy: req.user._id
};
// we create our new post in our database
Question.create(newQuestion, (err, question) => {
if (err) {
res.redirect('/');
throw new Error(err);
}
// we insert our newQuestion in our posts field corresponding to the user we found in our database call
user.questions.push(newQuestion);
// we save our user with our new data (our new post).
user.save((err) => {
return res.send('sucess!');
});
})
});
}
Router.js
module.exports = function(app) {
// Initializing route groups
const apiRoutes = express.Router(),
userRoutes = express.Router(),
authRoutes = express.Router(),
questionRoutes = express.Router();
//=========================
// Auth Routes
//=========================
/** ROUTES BELOW WORK FINE -- ONLY DEALS WITH POST TO /questions
*
app.use middle ware sets /auth as auth route (everything goes through /api/auth)
apiRoutes.use('/auth', authRoutes);
apiRoutes.get('/dashboard', requireAuth, function(req, res) {
res.send('It worked! User id is: ' + req.user._id + '.');
});
// Set user routes as a subgroup/middleware to apiRoutes
apiRoutes.use('/user', userRoutes);
// View user profile route
userRoutes.get('/:userId', requireAuth, UserController.viewProfile);
// Test protected route
apiRoutes.get('/protected', requireAuth, (req, res) => {
res.send({ content: 'The protected test route is functional!' });
});
// Registration route
authRoutes.post('/register', AuthenticationController.register);
// Login route
authRoutes.post('/login', requireLogin, AuthenticationController.login);
*/
// Problem Area --> Making POST req to /questions
apiRoutes.post('/questions', requireAuth, QuestionController.addQuestion);
// Set url for API group routes
app.use('/api', apiRoutes);
};
You've your schema defined to accept question ids for a user.
questions: [
{
type: Schema.Types.ObjectId,
ref: 'Question'
}
After you save with Question.create(newQuestion, (err, question)... the callback attribute question has the updated data, one with the ObjectId.
Now you add this ObjectId value to your existing questions array that you got from findById on User model.
user.questions.push(question._id);
Mongoose will use the questionId to fill your question object when you use populate on questions array, but thats part for retrieving information.
I've found a number of examples showing the ability to set your own _id property to something other than the default ObjectId in a mongoose schema:
var personSchema = new mongoose.Schema({
_id: Number,
name: String
});
A few questions I have:
1) Does this auto increment and handle everything else for me? The only examples I've seen don't show any additional code to ensure this a unique and incremented key in MongoDB.
2) This doesn't seem work for me. When I remove the _id from the schema, I get documents posting correctly as expected, but when I add it (_id: Number), nothing gets added to the collection, and Postman returns just an empty object {}. Here's the relevant code:
var personSchema = new mongoose.Schema({
_id: Number,
name: String
});
var Person = mongoose.model("Person", personSchema);
app.get("/person", function (req, res) {
Person.find(function (err, people) {
if (err) {
res.send(err);
} else {
res.send(people)
}
});
});
app.post("/person", function(req, res) {
var newPerson = new Person(req.body);
newPerson.save(function(err) {
if (err) {
res.send(err);
} else {
res.send(newPerson);
}
});
});
A POST request returns {}, and neither the collection nor document are created.
If you include an _id field in your schema definition, when you insert a document you must supply it with your own manually generated _id. If you don't, the document will not get inserted.
Alternatively, if you do not include an _id field in your schema definition, Mongoose will create this for you automatically, when the document is inserted, and it will be of type ObjectId (which is the default way that MongoDB sets the _id field on documents).
I'm using the following schema located in my /routes/schema.js file...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
username: String,
password: String,
name: String,
last: String,
year: Number,
degree: String
});
var User = mongoose.model('User', userSchema);
module.exports = {
User: User
}
In my /routes/register.js file I am storing some information using POST data...
var User = require('../routes/schema').User;
exports.postRegister = function (req, res) {
var u = new User({
username: req.body.reg_username,
password: req.body.reg_password,
name: req.body.reg_name,
last: req.body.reg_lastname,
year: req.body.reg_year,
degree: req.body.reg_degree
});
u.save(function (err) {
if (err) {
throw err;
}
else {
console.log("saved");
res.render('index', { title: 'Express' });
}
});
}
Everything gets saved fine in my Database. But now, this register.js file redirects the user back to /routes/index.js where the user must then sign in using some credentials stored in the database.
So in my index.js file I need to check if username and password exist together in a collection in my database, I tried the following...
var User = require('../routes/schema').User;
exports.signin = function (req, res) {
User.findOne({
username: req.body.log_username,
password: req.body.log_password
}, function (err, docs) {
if (docs.length) {
console.log("name exists");
}
else {
console.log("no exist");
}
});
};
I used the findOne function with the same Schema to check if username and password exist in a collection in the database, but it doesn't work properly. I seem to get a multiple connection error and I do not know how to avoid it.
When I try to login using some credentials already in the database, the console prints out no exist meaning the else statement in exports.signin is reached.
The value of the docs will be null if the object is not found in the collection.
If the user enters wrong credentials, you will be calling docs.length on null object, which will cause an error. Use docs != null instead, to avoid calling length on null object.
try it docs.length !== 0 this is check docs field is existed or empty.
I want to delete a Mongodb document by id, passing it to Express route.
In the console, I receive a message that says it is deleted.
GET /api/videolinks 304 94.792 ms - -
Removed id= 562b905f633288ac0d8b4567
DELETE /api/videolinks/562b905f633288ac0d8b4567 200 68.550 ms - 19743
But it is not.
> db.hyperlinks.find({"_id": ObjectId("562b905f633288ac0d8b4567")})
{ "_id" : ObjectId("562b905f633288ac0d8b4567"), "file" : "http://storage.akamai.com/get/b113/p/coub/simple/cw_file/79632d71313/9aedca2cd4d3094e75834/iphone_hellosergii_iphone.mp4" }
My Angularjs factory:
/*global angular*/
angular.module('myService', [])
// each function returns a promise object
.factory('Videolinks', ['$http',function($http) {
return {
get : function() {
return $http.get('/api/videolinks');
},
delete : function(id) {
return $http.delete('/api/videolinks/' + id);
}
};
}]);
My route.js
var path = require('path');
var Videolink = require('./models/mydb');
var mongodb = require('mongodb');
// Get links
function getLinks(res){
Videolink.find(function(err, hyperlinks) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err) {
res.send(err);
}
res.json(hyperlinks); // return all videos in JSON format
});
}
module.exports = function(app) {
// api ---------------------------------------------------------------------
// use mongoose to get all videos in the database
app.get('/api/videolinks', function(req, res) {
getLinks(res);
});
// delete a video
app.delete('/api/videolinks/:video_id', function(req, res) {
Videolink.remove({
_id : mongodb.ObjectID(req.params.video_id)
}, function(err) {
if (err) {
res.send(err);
}
console.log("Removed id= " + req.params.video_id);
getLinks(res);
});
});
// application -------------------------------------------------------------
app.get('*', function(res) {
res.sendFile('index.html', {root: path.join(__dirname, './public')}); // load the single view file
});
};
The app.get functionality works pretty well here.
What could be wrong with app.delete?
Here is my DB schema in models/mydb
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var db_schema = new Schema({
//text: String
_id: String,
source: String,
orig_page: String,
likes: Number,
title: String,
file: String,
video_mobile_res: String,
video_high_res_mutes_muted: String,
audio_high_res: String,
video_med_res_muted: String,
audio_med_res: String
}, {collection: 'hyperlinks'});
module.exports = mongoose.model('Videolink', db_schema);
Your particular problem is that you defined the _id field as a String in your schema:
var db_schema = new Schema({
_id: String,
...
Take that out and your code should work fine. You may have even uncovered a mongoose bug, since you are supposed to be able to specify the _id field type. Maybe some mongoose expert can tell us more.
Im running Express on my application with a delete route below:
router.route('/lists/:id')
.delete(function(req, res){
Entry.remove({
_id: req.params.id
}, function(err, list){
if(err)
res.send(err)
list.title = req.body.title;
res.json({message: 'successfully deleted'});
console.log('DELETE on /lists/'+ req.params.id);
});
});
Here is my Mongoose schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ListSchema = new Schema({
title: String
});
module.exports = mongoose.model('List', ListSchema);
When my application hits the delete route, my terminal logs the appropriate statement, but the model is not deleted from the database. When I call fetch on the collection, all of there records are still there.
I am using a very similar approach on a different collection of data on my website, and it works fine, so Im really at a loss for why this is happening.
Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assiged is an ObjectId to coincide with MongoDBs default behavior
Try passing the _id as ObjectId:
var ObjectId = require('mongoose').Types.ObjectId;
var query = { _id: new ObjectId(req.params.id) };