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).
Related
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);
I am working on a ExpressJS and MongoDB project that involves parsing dynamic mongoose schema. The way I set up the dynamic schema is and parse it :
Step-1
//Creating a mongoose schema
var userSchema = mongoose.Schema({
measurements : [
mongoose.Schema({
time: String
})
]});
Step-2
//Creating a mongoose model for the schema
var User = mongoose.model('User', userSchema);
var user = new User();
user.measurements = [{time:req.body.time}]
//save the info
user.save(function(err) {
if (err)
res.send(err);
res.send({message: "User Info created"});
});
});
Expected result :
A example with JSON validator to explain my goal clearly:
But the issue is my code posts data in the following way to the mongo database :
I was wondering if it is possible to post new array object with time attribute instead of having the comma separated values.
Any thoughts and suggestions on this would be appreciated.
Thanks
You are doing it the wrong way.
Try this:
var user = new User();
user.measurements.push({time:req.body.time});
//save the info
user.save(function(err) {
if (err)
res.send(err);
res.send({message: "User Info created"});
});
});
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.
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) };
I am currently working on a small single page app that lets users login with PassportJs and Mongoose.
One of the things I am trying to do is allow users to login and each user has a unique todo/task list which are items associated to that user.
I have been able to do the first part...users can login and express/passport session is accessed using jade #{user.username}, so when logged in the user see "Welcome, [user.username]".
Now I add a form (accessible when user logged in) and the form says undefined. I'm not sure if its my Mongoose schema design or Routes that are causing the problem. Thanks for reading this and here is my code:
Mongoose Schema
mongoose.connect('mongodb://localhost/poplivecore')
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var user = new Schema({
username: String,
password: String,
email: String,
todos: [Todo]
});
var Todo = new Schema({
name: {type: String, default : ''},
user: {type: Schema.ObjectId, ref: 'user'},
createdAt : {type : Date, default : Date.now}
})
var Todo = mongoose.model('Todo', Todo);
var user = mongoose.model('user', user);
Here are my Express routes:
//WORKING....This route is the one that a logged in user sees, form posts with
app.get('/home', ensureAuthenticated ,function(req, res){
res.render('home', { user: req.user});
});
//WORKING...This route allows user to post/submit the login
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res) {
res.redirect('/home');
});
//WORKING....This route allows user to create a user/account
app.post('/create', function(req, res, next){
var user = new user({
"username": req.body.username,
"password" : req.body.password,
"email" : req.body.email});
user.save(function (err) {
if (!err) {
res.redirect('/home');
}
else {
res.redirect('/');
}
});
});
**//NOT WORKING..Post used in the form inside the logged in Area, that adds a 'todo'**
app.post('/todo', function(req, res){
var todo = new todo(req.body.name);
todo.save(function (err) {
if (!err) {
res.redirect('/home');
}
else {
res.redirect('/fail');
}
});
});
Jade Form, for Adding a todo
enter code here
form(method='post', action='/todo')
//input(type='hidden', value= user._id)#userId
fieldset
label Todo
div.input
input(name='todo.name', type='todo.name', class='xlarge')
div.actions
input(type='submit', value='Save', class='btn primary')
button(type='reset', class='btn') Cancel
I can post on github if you need to see more code...thanks.
Update as per 'numbers1311407' suggesion
*New post route for todo, also changed todo to 'Todo' in both schema and routes*
app.post('/todo', function(req, res){
var todo = new Todo({name : req.body["Todo.name"]});
todo.save(function (err) {
if (!err) {
res.redirect('/home');
}
else {
res.redirect('/fail');
}
});
});
There are at least two problems here that would cause this to not work:
The name of the input passed by your form is todo.name, and you're referencing it as req.body.name in the route.
mongoose models are instantiated with an attributes object, but you're just giving it a string (which, actually, is null currently because of the first issue).
So for your route to work it would look more like this:
app.post("/todo", function (req, res) {
var todo = new Todo({name: req.body["todo.name"]});
todo.user = req.user._id;
// ...
});
If you wanted to pass todo attributes as a parameter object, you'd want to name them with brackets todo[name], rather than dots. This would result in the todo attributes being on object on the req.body, e.g.:
app.post("/todo", function (req, res) {
console.log(req.body.todo); //=> { name: "whatever" }
// ... which means you could do
var todo = new Todo(req.body.todo);
todo.user = req.user._id;
// ...
});
Some other things you might want to change:
As #NilsH points out, you don't want to pass the user id in the form, as that would allow anyone to make a todo for anyone else just by knowing their ID. Rather since you're using passport, make use of the user in the session. You should have access to the user ID through the passport determined user, like req.user._id. I added this to both examples above.
The type of your form input is todo.name. It should be text (that's what the browser is treating it as anyway).
Not necessarily an error, but model names are conventionally capitalized. This also solves an issue your code has above in that you're redefining todo when you say var todo = new todo(...).