Store objects in array using mongodb, node and express - node.js

I'm trying to build a messaging system for my school project. I have created a schema in mongodb that looks like this:
var userSchema = new mongoose.Schema({
firstName: String,
lastName: String,
messages: []
});
I want to store an object in the messages that looks something similar to this:
{
from: 'fromUsername',
to: 'toUsername',
time: new Date(),
msg: 'message is here'
}
I want to be able to store that in the schema under the messages array. Is there a way to push that to the shcema? Not sure how to approach this task. Thanks!

You can define the schemas separately with the message schema embedded as part of the user document (as items within the messages array):
var messageSchema = new mongoose.Schema({
from: String,
to: String,
time: { type: Date, default: Date.now },
msg: String
})
var userSchema = new mongoose.Schema({
firstName: String,
lastName: String,
messages: [messageSchema]
});
mongoose.model('User', userSchema);
To add the given message to the messages array, follow the pattern:
// retrieve user model
var User = mongoose.model('User');
// create user instance
var user = new User({
firstName: 'Alice',
lastName: 'Bob'
});
// create a message
user.messages.push({
from: 'fromUsername',
to: 'toUsername',
msg: 'message is here'
});
You have an option to exclude the time field since you would have defined its default value when you persist your model.
user.save(function (err, user) {
if (!err) console.log(JSON.stringify(user, null, 4));
});

You can use th $push operator to appends your object value in the message array.
An example of how to use $push for your userSchema
// How to update a user already created
var User = mongoose.model('User');
User.update(
{ _id: id },
{ $push: {messages : {
from: 'fromUsername',
to: 'toUsername',
time: new Date(),
msg: 'message is here'}}
})

Related

Is there a problem with not following the structure of the created model and saving data with different information?

I'm a newbie and I'm doing a backend with nodeJS + Express + mongoDB.
So I have this model:
const user = new Schema({
email: String,
password: String,
lastName: String,
firstName: String
})
module.exports = model('User', user);
Then when a user signs Up I save the data :
const createUser = new User({
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
id: req.body.id,
lastName: req.body.lastName,
firstName: req.body.firstName,
photoUrl: req.body.photoUrl,
});
createUser.save((err, user) => {
if (err) {
res.status(500).send({message: err});
}else{
res.send({message: 'Complete'});
}
}
So I don't know If when I add new data "photoUrl" that doesn't exist in my main model it could affect the app or with other CRUD functions
Mongoose by default have strict: true flag on schema which basically means that values passed to model constructor that were not specified in the schema do not get saved to the db. So basically all the extra fields passed will be just skipped.
You will have to expicitly disable the strict in order to add the field that is not specified in the DB.
Following example taken from mongoose documentation
// set to false..
const thingSchema = new Schema({..}, { strict: false });
const thing = new Thing({ iAmNotInTheSchema: true });
thing.save(); // iAmNotInTheSchema is now saved to the db!

Mongoose - inserting subdocuments

I have a user model, and a log model. The log model is a subdocument of user model. So in my user model I have:
var mongoose = require('mongoose');
var Log = require('../models/log');
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
Log
]
});
Then in my 'Log' model I have:
var mongoose = require('mongoose');
var logSchema = new mongoose.Schema({
logComment: {
type: String,
},
});
module.exports = mongoose.model('Log', logSchema);
So upon creation of a 'user', the 'logsHeld' always begins empty. I want to know how to add subdocuments to this user model.
I've tried doing this POST method:
router.post('/createNewLog', function(req, res) {
var user = new User ({
logssHeld: [{
logComment: req.body.logComment
}]
});
user.save(function(err) {
if(err) {
req.flash('error', 'Log was not added due to error');
return res.redirect('/home');
} else {
req.flash('success', 'Log was successfully added!');
return res.redirect('/home');
}
});
});
But this doesn't work. It also includes a 'new User' line, which I don't think I need given this would be for an existing user.
You need to use the logSchema instead of the Log model as your subdocument schema in User model. You can access the schema as follows:
var mongoose = require('mongoose');
/* access the Log schema via its Model.schema property */
var LogSchema = require('../models/log').schema; // <-- access the schema with this
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [LogSchema]
});
Picking up from your comments in another answer where you are facing another issue
WriteError({"code":11000,"index":0,"errmsg":"E11000 duplicate key
error index: testDB.users.$email_1 dup key:
you are getting this because there's already a document in your users collection that has most probably a null value on the email field. Even though your schema does not explicitly specify an email field, you may have an existing old and unused unique index on users.email.
You can confirm this with
testDB.users.getIndexes()
If that is the case and manually remove the unwanted index with
testDB.users.dropIndex(<index_name_as_specified_above>)
and carry on with the POST to see if that has rectified the error, I bet my $0.02 that there is an old unused unique index in your users collection which is the main issue.
Try using logSchema which references only the subdocument schema, Log refers to the entire contents of ../models/log
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
logSchema
]
});
Documentation: http://mongoosejs.com/docs/subdocs.html
Try push to insert item in array in mongoose
var user = new User;
user.logssHeld.push({
logComment: req.body.logComment
});
user.save(function(err, doc) {
//DO whatever you want
});
see the docs here

How to get around E11000 MongoError without deleting 'unique: true'

I am trying to build a forum in order to learn the MEAN stack. I ran into an issue while using mongoose...
I have this...
var UserSchema = new Schema({
id: ObjectId,
firstName: String,
lastName: String,
role: String,
email: {
type: String,
unique: true
},
password: String,
workers: [WorkerSchema]
});
var TopicSchema = new Schema({
id: ObjectId,
title: String,
moderator: UserSchema,
posts: [PostSchema]
});
var Topic = mongoose.model('Topic', TopicSchema);
app.post('/topics', requireLogin, function(req, res) {
User.findOne({"email": req.session.user.email}, function(err, user) {
if (user.role == "moderator" || user.role == "admin") {
var topic = new Topic({
title: req.body.title,
moderator: req.session.user,
posts: []
});
topic.save(function(err) {
if (err) console.log(err);
res.status(204).end();
});
}
});
});
My issue is this... When I POST a topic to /topics, it works the first time, populating the topics collection with one item. But then, when I POST to /topics again, from the same user, I get an E11000 MongoError that looks like this:
message: 'E11000 duplicate key error index: MY_MONGO_DB.topics.$moderator.email_1 dup key: { : "myuser#example.com" }'
I know that removing the 'unique: true' property from the email field of UserSchema would fix this issue, but I don't want to remove that uniqueness property since I use it elsewhere in my code to ensure that users are unique by email.
Is there any way around this? In other words, is there any way to keep the 'unique: true' property and also retain the ability of users to be able to post multiple topics without triggering the E11000 error?
What you did was to embed the user. In your database, the resulting document would look something like
{
...
moderator: {..., email: "john#example.com"}
}
Which, of course, would violate the unique constraint if you have the same person as a moderator twice.
What you should do instead is to reference the user in your schema:
var user = mongoose.model('User', UserSchema);
var TopicSchema = new Schema({
id: ObjectId,
title: String,
moderator: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
posts: [PostSchema]
});

MongoDB: index on collection names themselves

Say I have a simple user schema:
var userSchema = new mongoose.Schema({
username: String,
password: String,
notifications: [{
message: String,
dateCreated: Date,
}]
});
module.exports = mongoose.model('user',userSchema);
but what if we have a lot of users and we break apart the model, making notifications it's own collection like so:
var userSchema = new mongoose.Schema({
username: String,
password: String,
});
var notifsSchema = new mongoose.Schema({
message: String,
dateCreated: Date,
});
module.exports = function getModel(userId){
return mongoose.model('notifs_' + userId, notifsSchema)
}
so my question is: if we make notifications collections by user, so we have 200 users, therefore 200 notifications collections - is MongoDB smart enough to be able to index by collection name somehow? So if we have 100,000 users MongoDB can fins the notifications collection called 'notifs_394939329443'?

Express: Embed document in the existing document

I am developing an application in Express, Node and Mongo being the database. I have a collection users, and user can have mutiple registered-IDs. It like a one-to-many relationship. I m trying to embed a document in the user collection like this:
post(function (req, res, next) {
var pid=req.body.pid;
var sid=req.body.sid;
var rfname=req.body.rfname;
var des=req.body.des;
var brand=req.body.brand;
var model=req.body.model;
var serial=req.body.serial;
var location=req.body.location;
var arr={pid: 'pid', sid: 'sid', rfname: 'rfname' ,des: 'des', brand: 'brand', model: 'model' ,serial: 'serial', location: 'location'};
mongoose.model('User').findOne({'pemail': req.session.email}, function (err, user){
if(err){
} else {
user.registeredId = arr;
user.save(function(err){
if(err){
} else {
res.render('user/register', {'success': 'dfhlaksdhfh'});
}
})
}
});
}
My user schema is like this:
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
email: String,
password: String,
fname: String,
lname: String,
plang: String,
slang: String,
country: String,
state: String,
city: String,
postalcode: String,
address1: String,
address2: String,
pemail: String,
semail: String,
age: String,
gender: String,
pphone: String,
sphone: String,
q1: String,
a1: String,
q2: String,
a2: String,
cfname: String,
clname: String,
cemail: String
});
mongoose.model('User', userSchema);
Guide me, what am i doing wrong, because it does not embed document in the existing document. Do I need to define that in schema, if so, then how?
In your schema definition, the field registeredId is not defined and by default through the strict option, Mongoose ensures that values passed to your model constructor that were not specified in our schema do not get saved to the db, hence it is not creating the modified document.
You can either explicitly define the field in your schema or set the strict option to false in your schema definition:
// set to false..
var userSchema = new Schema({..}, { strict: false });
and then implement one of the findAndModify() methods like findOneAndUpdate() to update your user document by pushing the new object to the new array field registeredId. So you could re-write your post function as:
post(function (req, res, next) {
var User = mongoose.model('User'),
pid=req.body.pid,
sid=req.body.sid,
rfname=req.body.rfname,
des=req.body.des,
brand=req.body.brand,
model=req.body.model,
serial=req.body.serial,
location=req.body.location,
arr = {
'pid': pid,
'sid': sid,
'rfname': rfname,
'des': des,
'brand': brand,
'model': model,
'serial': serial,
'location': location
},
condition = { 'pemail': req.session.email },
update = {
"$push": { 'registeredId': arr }
};
User.findOneAndUpdate(
condition,
update,
function (err, doc){
if(err){}
else {
// doc contains the modified document
res.render('user/register', {'success': 'dfhlaksdhfh'});
}
}
);
});

Resources