Correct structure for grouping data in Mongoose Schema - node.js

I've created a Mongoose Schema that looks like this:
var UserSchema = new Schema({
user: [{
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
index: { unique: true }
},
password: {
type: String,
required: true
},
mobile: Number
}],
account: [{
locked: {
type: Boolean,
default: false
},
accountType: {
type: String,
default: "guest"
},
failedLogins: {
type: Number,
default: 0
}
}],
reset: [{
resetToken: String,
resetExpirey: Date
}],
details: [{
accountCreated: Date,
lastLogin: Date
}]
});
As you can see I've tried to group certain fields. Is this the correct way to do it? I'm now having trouble referencing the fields. I get an error when I try this:
User.create({
user.name : req.body.name,
user.email : req.body.email,
user.password: req.body.password
}, function(err) {
if (err) res.send(err);
});
Error is unexpected token '.' in user.name

Your create statement still needs to be proper javascript, so your left-side object literals will need to be strings.
User.create({
'user.name' : req.body.name,
'user.email' : req.body.email,
'user.password': req.body.password
}, function(err) {
if (err) res.send(err);
});
Furthermore, because Mongoose requires you to have an array instead of allowing proper sub-objects, you'll need to actually insert these as an array.
var user = {user: [{name:req.body.name, email: req.body.email, password: req.body.password}]};
User.create(user) ...
As to the "is it worth it" to do it like this, my opinion is: no. Just put all these things in the root object unless you plan on having more than one user or more than one account in this one document.

Related

How to search in multiple collections in MongoDB using Mongoose

I have two collections User and UserType :-
var User = new mongoose.Schema({
username: {
type: String,
required: true,
},
userType: {
type: ObjectId,
ref: "UserType",
required: true,
},
});
var UserTypeSchema = new mongoose.Schema(
{
type: String,
type_code: Number,
type_description: String,
},
{ timestamps: true }
);
I want to search user based on username and typecode which is in UserType Collection.
I tried this code: -
User.findOne({
username: mobileNumber,
userType: { type_code: userTypeCode },
})
.populate("userType");
please correct this query.
you must to filter out populate results, with match option
In your case answer would be::
User.findOne({
username: mobileNumber,
}).populate({
path: "userType",
match: { type_code: userTypeCode },
});
you can check the documentation

Mongoose Discriminators unable to add dicriminator details

Im currently working on adding discriminators to my express rest api. I have added different types of users to the user schema using the discriminators as different user require additional information. The problem I am facing is that when I post to the api get no errors when adding the information and only the general information is added to the schema, the details within the discriminators are ignored.
The schema is as follows:
var options = { discriminatorKey: 'type' };
var UserSchema = new Schema({
local: {
email: {
type: String,
sparse: true,
lowercase: true,
},
password: { type: String },
},
facebook: {
id: String,
token: String,
email: String,
name: String,
profileIMG: String,
},
twitter: {
id: String,
token: String,
displayName: String,
username: String
},
google: {
id: String,
token: String,
email: String,
name: String,
profileIMG: String,
}
}, options);
var addressSubschema = {
street: {
type: String,
required: true
},
number: {
type: String,
required: true
},
city: {
type: String,
required: true
},
};
var workingHoursSchema = {
start: {
type: String,
required: true
},
finish: {
type: String,
required: true
}
};
var adminSchema = new Schema({
description: {
type: String,
required: true
},
category: {
type: String,
required: true
},
workingHours: workingHoursSchema,
address: addressSubschema,
workingRadius: {
type: Number,
required: true
},
}, options);
var User = mongoose.model('User', UserSchema);
var Admin = User.discriminator('AdminUser', adminSchema);
module.exports = User;
I then export the model and when saving a new user I get a success however the admin details are not saved.
User.findOne({'local.email': email}, function(err, existingUser) {
if (err) { return next(err) }
if (existingUser) {return res.status(422).json({error: "Email already exists"})}
var user = new User({
"local.email": req.body.email,
"local.password": req.body.password,
"description": req.body.description,
"category": req.body.category,
"workingRadius": req.body.workingRadius,
"street": req.body.street,
"number": req.body.number,
"city": req.body.city,
"start": req.body.start,
"finish": req.body.finish
});
user.save(function(err) {
if (err) { return next(err) }
res.json({success: true});
});
});
Im new to using the discriminator so any help is greatly appreciated.

How to update this model that contains an array of objects in mongoose

I was wondering how I can update the array of likes with mongoose:
var postSchema = new mongoose.Schema({
author: String,
content: String,
date: String,
likes: [{theID: String}],
numDate: Number
});
var UserSchema = mongoose.Schema({
username: {
type: String
},
password: {
type: String
},
email: {
type: String
},
first: {
type: String
},
posts: [postSchema],
last: {
type: String
},
followers: [{theID: String}],
following: [{theID: String}],
img: { data: Buffer, contentType: String },
admin: {type: Boolean, default: false}
});
I can push things like new posts to a certain user in the database by
doing this:
User.update({_id: req.user.id}, {
$push: {"posts": {_id : req.body.theData}}
}, function(err, user){
res.redirect('profile');
});
Is there a similar way I can look at a specific user and then a specific post that the user has and update it to push a string to the likes array?
First Of all you need to select the post where you want to update like dislike, you can do it with the help of _id of post {_id: req.user.id,_id:posts._id} then you will need to update like array that can be done this way {$push: {"posts.$.likes": req.user.anotherUserId}} //anotherUserId is of user who liked it. same way you can take a pull of user id if user dislikes the post to remove id from array.
User.update({_id: req.user.id,_id:posts._id}, {
$push: {"posts.$.likes": req.user.id}
}, function(err, user){
});

Mongoose Add New Field To Collection (Node.js)

I have a schema:
var userSchema = new Schema({
name: String,
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
admin: Boolean,
created_at: Date,
updated_at: Date
});
Let's assume I have made 100 Users using this schema.
Now I want to change the schema:
var userSchema = new Schema({
name: String,
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
admin: Boolean,
created_at: Date,
friends: [Schema.Types.ObjectId], //the new addition
updated_at: Date
});
I need all new Users to have this field. I also want all of the 100 existing Users to now have this field. How can I do this?
You can use Mongoose Model.update to update all your documents in the collection.
User.update({}, { friends: [] }, { multi: true }, function (err, raw) {
if (err) return handleError(err);
console.log('The raw response from Mongo was ', raw);
});
I don't recommend to do it in production if the collection is big, since it is a heavy operation. But in your case it should be fine.
Using the query interface in a client app or your terminal you could do:
db.users.updateMany({
$set: { "friends" : [] }
});
Here's the docs reference.
it doesn't work for me :x
Here is my code
let test = await this.client.db.users.updateMany({
$set: { "roles" : [] }
});
and the output
{ ok: 0, n: 0, nModified: 0 }
I don't know how to do, i tried a lot of things and uh it doesn't work :'(
EDIT: I found, here is my code
await this.client.db.users.updateMany({ }, [ {$set : { "roles": []} } ]);

Need some clarification on mongoose/mongodb populate command

Hello so I am making a basic app with users and posts.
I followed the mongoose documentation on population (http://mongoosejs.com/docs/2.7.x/docs/populate.html) and setup my Schemas so that the users and be connected to posts
var userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
email: String,
created_at: Date,
updated_at: Date,
admin: Boolean,
posts: [{ type: mongoose.Schema.ObjectId, ref: 'Post' }]
});
var postSchema = new mongoose.Schema({
_user : [{ type: mongoose.Schema.ObjectId, ref: 'User' }],
audioFile: { type: String, required: true },
imageFile: { type: String },
title: { type: String, required: true },
artist: { type: String, required: true },
start: { type: String, required: true },
stop: { type: String, required: true },
genre: { type: String, required: true },
tags: [{ type: String }]
});
app.get('/', function (req, res){
Post.find({}, function(err, allPosts){
if(!err){
res.render('main.njk', {
posts : allPosts,
title : 'Title',
isLogged : req.session.isLogged,
user : req.session.user,
messages : req.flash('alert')
});
} else { return done(err); }
});
});
Thats all fine and gravy and I can run a foreach loop on allPosts to pull each one in my HTML, but when I try to think of how I am going to display all the posts with their respective users attached to each post I am unsure of how to connect the two since all the examples in the mongoose doc is just mainly for findOne.
I was thinking something like this
app.get('/', function (req, res){
Post.find({}, function(err, allPosts){
if(!err){
allPosts.populate('_user', ['username']);
allPosts.exec(function (err, users){
if(err) console.log(err);
console.log(users);
});
res.render('main.njk', {
posts : allPosts,
title : 'Spaurk.net',
isLogged : req.session.isLogged,
user : req.session.user,
messages : req.flash('alert')
});
} else { return done(err); }
});
});
but that doesn't work of course.
So I was wondering if anyone with experience with this situation would be able to help me solve this.
Thanks a lot for any input.
EDIT, thanks to Daves help I was able to get the populate to work properly, I just cant pull the fields I want correctly with
Post.find({}).populate('_user').exec(function(err, allPosts){
In my loop {% for post in posts %}
, when I do post._user it shows the whole user schema, but when I do post._user.username it doesn't return anything. I am unsure as to why this is.
The proper way to structure a populate on a query is like this:
Post.find({})
.populate('_user')
.exec((err, allposts){...})
Then you will have an array of your Posts with the _user array populated. If you need to access a property of a user, you will need to do another loop through the _user array or specify with use you want to use _user[0].<property>

Resources