How to parse request (or end points) to query mongoose - node.js

I am going to to implement a web api like this
POST /groups/:groupname/chats/:chatType
There could be several groups and each group has at most two chats, a private one or a public one.
Currently, in my /models directory, two related schemas look like this:
// group.js
...
var groupSchema = new mongoose.Schema({
groupname: {type: String, required: true, index:{unique: true}},
privateChat: {type: mongoose.Schema.Types.ObjectId, ref: 'Chat'},
publicChat: {type: mongoose.Schema.Types.ObjectId, ref: 'Chat'}
});
module.exports = mongoose.model('Group', groupSchema)
// chat.js
var chatSchema = new mongoose.Schema({
chatType: String, // public or private
message: [{text: String}]
});
module.exports = mongoose.model('Chat', chatSchema);
So the question is how can I post a message like "Hello World!" to
/groups/boygroup/chats/private
...
I have finished the request GET /groups/:groupname by findOne() method like this:
router.get('/groups/:groupname', function(req, res) {
var groupname = req.body.groupname || req.params.groupname;
Group.findOne({
groupname: groupname
}, function(err, group) {
if (err)
return next(err);
if (!group) {
res.status(404).send({
success: false,
message: "group not found"
});
} else {
res.json(group);
}
});
});
But I have no idea how to get to a specific chat in a specific group. Maybe my mongoose schema is not good.
Any suggestion is appreciated.

Related

Mongoose query in an Object

Question, I got a schema using mongoose which created an Object. I don't know how to query the author id which will return the list of the object under the author Id
var mongoose = require("mongoose");
var bookedSchema = new mongoose.Schema({
origin: String,
destination: String,
author: { id: { type: mongoose.Schema.Types.ObjectId, ref: "User"}, username: String},
Date: {type: Date, default: Date.now}
});
module.exports = mongoose.model("Booked", bookedSchema);
On my route I have query find({}) i want to query the author id instead of {} and it will return the list of object under the author ID. i tried the findById(author:{id:req.user._id}) but it returned null answer. any ideas how to do that. Thank You!
router.get('/myAccount', function(req, res){
Booked.find({}).exec(function(err, booked){
if(err){
console.log(err);
// res.redirect('back');
}else{
console.log(booked)
res.render('accounts/myAccount', {booking:booked});
}
});
});
you should use .populate() for refered documents to populate them.
change this:
Booked.find({}).exec(function(err, booked)
to:
Booked.find({}).populate('author').exec(function(err, booked)
or if you need to find a document by the refered author id you can use this:
Booked.find({}).populate({
path: 'author',
match: { id: { $eq: req.user._id }}
}).exec(function(err, booked)

How to associate the ObjectId of the parent schema to the child schema in the same transaction?

I have two types of entities, users and families, with a many-to-one relationship between families and users, so one family can have many users but one user will only have one family. I attempted to create a Mongo schema that tries to achieve this relationship, but not sure if this is the right way to do it.
I have a button on my HTML page that when clicked, will generate a family code and also create a new family attribute for the family entity. However, I'm unable to connect that newly generated family.ObjectId to the user's familyid attribute in the user entity.
Any idea what I'm doing wrong?
My Models:
Family Model:
var mongoose = require("mongoose");
var shortid = require('shortid');
//Set Schema
var familySchema = mongoose.Schema({
individuals: [{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}],
familyCode: {
type: String,
'default': shortid.generate
}
});
//setup and export the model
module.exports = mongoose.model("Family", familySchema);
Users Model:
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
username: String,
password: String,
image: String,
firstName: String,
lastName: String,
accountid: String,
isAdmin: {type: Boolean, default: false},
userlabel: String,
familyid:
{ type : mongoose.Schema.Types.ObjectId,
ref: "Family"}
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
My Route:
router.post("/familySetup", function(req, res){
if(!req.body.familyid){
var familyCode = shortid.generate();
console.log(familyCode);
// var individuals = {id:req.user._id}
var newFamily = {familyCode:familyCode};
Family.create(newFamily, function(err, newFamily){
if(err){
req.flash("error", "something seems to have gone amiss. Please try again.")
console.log(err);
res.redirect("home")
}else{
var updatedUser = {familyid:newFamily._id}
console.log(updatedUser);
User.findByIdAndUpdate(req.params.user_id, updatedUser, function(req, res){
if(err){
console.log(err);
}else{
//redirect to index
res.redirect("/familySetup");
}
});
}
});
}else{
alert("You already have a family account");
res.redirect("back");
}
});
Based on the error I get, I am able to create a familyCode and am able to create the variable, updatedUser. But it does not update the user with the new attribute. This is the error when I run the code:
ByJyRqb_Z
{ familyid: 59941dd6589f9a1c14a36550 }
events.js:141
throw er; // Unhandled 'error' event
^
TypeError: Cannot read property 'redirect' of null
at /home/ubuntu/workspace/mbswalay/routes/family.js:44:28
at Query.<anonymous> (/home/ubuntu/workspace/mbswalay/node_modules/mongoose/lib/model.js:3755:16)
at /home/ubuntu/workspace/mbswalay/node_modules/mongoose/node_modules/kareem/index.js:277:21
at /home/ubuntu/workspace/mbswalay/node_modules/mongoose/node_modules/kareem/index.js:131:16
at nextTickCallbackWith0Args (node.js:436:9)
at process._tickCallback (node.js:365:13)
It doesn't seem to be an error of mongodb, it's related to the route configuration, which seems make the response object to be null
User.updateOne(
{ _id: req.params.user_id },
{ $set: { familyid: newFamily._id } }
)
You have to set the value of an attribute using $set operator.

How to populate a mongoose schema

I have the following mongoose schemas
var postTable = mongoose.Schema({
userPost:{type : String},
dateCreated: {type: Date, default: Date.now},
_replies:[{type: mongoose.Schema.Types.ObjectId, ref: 'reply_table'}],
_creator:{type: mongoose.Schema.Types.ObjectId, ref: 'User'}
});
and
var reply_table = mongoose.Schema({
userReply:{type:String},
date_created:{type:Date, default: Date.now},
_post:{type: mongoose.Schema.Types.ObjectId, ref: 'post'},
_creator:{type: mongoose.Schema.Types.ObjectId, ref: 'User'}
});
var userPost = module.exports = mongoose.model("Post",postTable);
var userReply = module.exports = mongoose.model('reply_table',reply_table);
User can create post which will be entered into the Post table and other users can comment or reply to a post which will be entered into the reply_table.
I then try to populate the the post table like this
module.exports.getPost = function (callback) {
var mysort = { dateCreated: -1 };
userPost
.find({},callback)
.sort(mysort)
.populate('_creator','username')
.populate(' _replies')
.exec(function (err,post) {
if(err) throw err;
console.log(post)
});
};
When the console prints out the post it prints the post information and a object with the user information becausei have another schema setup for users, therefore I used .populate('_creator','username')
The problem is it wont print the reply information it only prints an empty array: reply[].
I'm pretty sure I'm doing everything right. I used the following code to insert information into the reply_table
//make a reply on a post
module.exports.make_reply = function (user_id,pid,reply,callback) {
var newReply = userReply({
_creator: user_id,
_post: pid,
userReply: reply
});
newReply.save(callback);
}
I know this question is very long but does anyone have any idea of what I might be doing wrong. I only want to populate the Post schema with information from the reply_table
I finally figured out a solution to my question. What i did was i created a function to insert the reply id into the post table. It basically get the comment by its id and push a reply into the _replies array in the post table.
//Insert reply into post table
module.exports.addReply = function (id,reply) {
userPost.update({_id:id},{$push:{replies:reply}},{multi:true},function
(err,post) {
});
}
When i use the getPost function it populates the reply table
module.exports.getPost = function (callback) {
var mysort = {dateCreated: -1};
userPost
.find({}, callback)
.sort(mysort)
.populate('_creator', 'username')
.populate('replies')
.exec(function (err) {
if(err) throw err;
});
};

Retrieve Array in Subdocument MongoDB

I have a Users model structure somewhat like this:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [models.Do.schema],
}
And the child "Do" schema somewhat like this (in a different file):
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
And I'm trying to figure out how to retrieve the todosDo array for the signed in user. This is what I've got so far:
// Get all "Do" todos from DB
// Experimenting to find todos from certain user
User.findById(req.user.id, function(err, user){
if(err){
console.log(err);
} else {
doTodos = user.todosDo, // this obviously doesn't work, just an idea of what I was going for
console.log(doTodos);
finished();
}
});
Am I referencing the child/parent wrong or am I just not retrieving the array right? Any help is greatly appreciated!
As far I guess you may want to edit as raw js objects so you need to use lean() function. without using lean() function user is mongoose object so you can't modify it.
can try this one:
User.findById(req.user.id)
.lean()
.exec(function (err, user) {
if(err){
console.log(err);
return res.status(400).send({msg:'Error occurred'});
}
if(!user) {
return res.status(400).send({msg:'User Not found'});
}
doTodos = user.todosDo;
console.log(user.todosDo); // check original todos
console.log(doTodos);
return res.status(200).send({doTodos : doTodos }); // return doTodos
});
and to refer child schema in parent schema from different model you can access a Model's schema via its schema property.
say in doSchema.js file
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
module.exports = mongoose.model( 'DoSchema', doSchema );
in user.js file
var DoModel = require('./doSchema');// exact path
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [DoModel.schema],
}
Thanks for your help everybody! My problem was that I needed to push all the newly created todos in the post route to todosDo, so then I could retrieve them at the get route. Everything's working now!

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]
});

Resources