Referencing between two collections not working on MongoDB - node.js

I am creating a user based node app and implementing the DHTMLX Scheduler within it. I have the scheduler working and showing events, the only problem is every user sees and edits the same calendar as of right now.
I tried creating schemas with references but it hasn't seemed to work.
player.js model (each individual user Schema):
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
calendar: {
type: Schema.Types.ObjectId, ref: 'calendar'
}
});
const User = mongoose.model('player', UserSchema);
module.exports = User;
calendar.js model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const schema = new Schema({
text: {type: String, required = true},
start_date: {type: Date, required = true},
end_date: {type: Date, required = true},
user: {type: Schema.Types.ObjectId, ref = 'User', required = true}
});
const calendar = mongoose.model('calendar', schema);
module.exports = calendar;
Implementing the calendar portion of my app.js
var db = require('mongoskin').db("myMongoDBCluster", { w: 0});
db.bind('calendar');
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/init', function(req, res){
db.calendar.insert({
text:"My test event A",
start_date: new Date(2018,8,1),
end_date: new Date(2018,8,5)
});
db.calendar.insert({
text:"My test event B",
start_date: new Date(2018,8,19),
end_date: new Date(2018,8,24)
});
db.calendar.insert({
text:"Morning event",
start_date: new Date(2018,8,4,4,0),
end_date: new Date(2018,8,4,14,0)
});
db.calendar.insert({
text:"One more test event",
start_date: new Date(2018,8,3),
end_date: new Date(2018,8,8),
color: "#DD8616"
});
res.send("Test events were added to the database")
});
app.get('/data', function(req, res){
db.calendar.find().toArray(function(err, data){
//set id property for all records
console.log(err);
for (var i = 0; i < data.length; i++)
data[i].id = data[i]._id;
//output response
res.send(data);
});
});
app.post('/data', function(req, res){
var data = req.body;
var mode = data["!nativeeditor_status"];
var sid = data.id;
var tid = sid;
delete data.id;
delete data.gr_id;
delete data["!nativeeditor_status"];
function update_response(err, result){
if (err)
mode = "error";
else if (mode == "inserted")
tid = data._id;
res.setHeader("Content-Type","application/json");
res.send({action: mode, sid: sid, tid: tid});
}
if (mode == "updated")
db.calendar.updateById( sid, data, update_response);
else if (mode == "inserted")
db.calendar.insert(data, update_response);
else if (mode == "deleted")
db.calendar.removeById( sid, update_response);
else
res.send("Not supported operation");
});

Mongo is a non-relational database, "reference" is a feature provided by mongoose. To make use of it you have to query through mongoose Models (objects exported from player.js and calendar.js)
var Calendar = require('./calendar');
Calendar.find()
.then(function (data) {
// ...
});
Calendar.find({user: 'yourUserId'}) // query by specific user
.then(function (data) {
// ...
});

Related

When making a POST request for a subdocument it comes back as undefined? mongoose, express

I'm trying a to make a post request to save new data to one of my subdocuments, but I'm getting an error when trying to access the subdocument in the function. It keeps coming back as undefined. How can I get a specific user by id and create and add new data the one it's subdocuments?
model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ClassworkSchema = new Schema({
name: String,
time: Date,
todo: String,
isDone: false
});
const OutcomesSchema = new Schema({
name: String,
time: Date,
todo: String,
isDone: false,
isApproved: false
})
const MeetupSchema = new Schema({
name: String,
time: Date,
location: String,
attended: false
})
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
classwork:{type: [ClassworkSchema], default: []},
outcomes: [OutcomesSchema],
meetups: [MeetupSchema],
});
module.exports = User = mongoose.model('users', UserSchema);
controller
classworkRouter.post("/:userId/", (req, res) => {
User.findById(req.params.user_id, (err, user) => {
if (err) return err;
new_classwork = new classwork();
(new_classwork.name = req.body.name),
(new_classwork.date = req.body.date),
(new_classwork.todo = req.body.todo),
(new_classwork.isDone = req.body.isDone);
console.log(new_classwork);
user.classwork = {};
user.classwork.name = req.body.classwork.name;
user.classwork.todo = user.classwork.todo;
if (user.classwork === undefined) {
user.classwork.push(new_classwork);
} else {
user.classwork = [new_classwork];
}
user.save(function (err, data) {
if (err) res.send(err);
res.json({ message: "work added", data: data });
});
});
});
you can see the error in the terminal in the following phto:
in this part of code
new_classwork = new classwork()
you shoud defined the new_classwrok like this :
let new_classwork = new classwork()
and new classwork() is not defined, you must to require Model of classwork in controller..
in schema file export schemas like this :
const User = mongoose.model('users', UserSchema);
const Classwork = mongoose.model('Classwork', ClassworkSchema );
module.exports = {
User : User ,
Classwork : Classwork
}
in controller.js
const {User} = require('../models/certification');
const {Classwork } = require('../models/certification');
after require models you can use new Crosswork like this :
note: Classwork with uppercase character
let new_classwork = new Classwork()

Nodejs Mongodb update multiple collections

In mongodb have two collections for now Event and Packages. So basically the model looks like this
Event Model
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const EventSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
eventname: {
type: String,
required : true,
},
eventdesc: {
type: String,
required : true,
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Event', EventSchema);
Package Model looks like this
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const PackageSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
eventpackages: {
type: Object,
required : false,
},
event: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Event'
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Package', PackageSchema);
Here I am trying to update an event so when the event will be updated the packages will be updated also. So in nodejs I have done like this
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
/* UPDATE EVENT */
router.put('/:id', function(req, res, next) {
upload(req, res, function(err) {
let EventData = {
eventname : req.body.eventname,
eventdesc : req.body.eventdesc,
}
let EventPackages = {
eventpackages : req.body.sections,
}
Event.findByIdAndUpdate(req.params.id, EventData, function (err, post) {
if (err) return next(err);
Package.findAndModify({
query: { event: req.params.id },
update: { $inc: { EventPackages } },
new: true,
upsert: true
})
res.json(post);
});
});
});
module.exports = router;
But its not working at all. If I will deleted the codes for package update it will work for events.
So can someone tell me how to make this work so that I can update multiple collections at a time.
you can try this,
var query = {
'event': req.params.id
};
var dataToUpdate = {
$set: {
///
}
};
Package.updateMany(query, datatoUpdate, function(err, result) {
if (err) return handleError(err);
return Promise.resolve(result);
});

Mongoose one-to-many

can you explain me how to organize mongoose models to create one to many connections? It is needed keep separate collections.
suppose i have stores and items
//store.js
var mongoose = require('mongoose');
module.exports = mongoose.model('Store', {
name : String,
itemsinstore: [ String]
});
//item.js
var mongoose = require('mongoose');
module.exports = mongoose.model('Item', {
name : String,
storeforitem: [String]
});
Am i doing it in the right way?
And how to access pass data to arryas?
Here is the code yo enter name to item. But how to enter id to array of id's (itemsinstore)?
app.post('/api/stores', function(req, res) {
Store.create({
name: req.body.name,
}, function(err, store) {
if (err)
res.send(err);
});
})
You should use model reference and populate() method:
http://mongoosejs.com/docs/populate.html
Define your models:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var storeSchema = Schema({
name : String,
itemsInStore: [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
var Store = mongoose.model('Store', storeSchema);
var itemSchema = Schema({
name : String,
storeForItem: [{ type: Schema.Types.ObjectId, ref: 'Store' }]
});
var Item = mongoose.model('Item', itemSchema);
Save a new item into an existing store:
var item = new Item({name: 'Foo'});
item.save(function(err) {
store.itemsInStore.push(item);
store.save(function(err) {
// todo
});
});
Get items from a store
Store
.find({}) // all
.populate('itemsInStore')
.exec(function (err, stores) {
if (err) return handleError(err);
// Stores with items
});
You can do using the best practices with Virtuals.
Store.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const StoreSchema = new Schema({
name: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
StoreSchema.virtual('items', {
ref: 'Item',
localField: '_id',
foreignField: 'storeId',
justOne: false // set true for one-to-one relationship
})
module.exports = mongoose.model('Store', StoreSchema)
Item.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ItemSchema = new Schema({
storeId: {
type: Schema.Types.ObjectId,
required: true
},
name: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Item', ItemSchema)
StoreController.js
const Store = require('Store.js')
module.exports.getStore = (req, res) => {
const query = Store.findById(req.params.id).populate('items')
query.exec((err, store) => {
return res.status(200).json({ store, items: store.items })
})
}
Keep in mind that virtuals are not included in toJSON() output by default. If you want populate virtuals to show up when using functions that rely on JSON.stringify(), like Express' res.json() function, set the virtuals: true option on your schema's toJSON options.
// Set `virtuals: true` so `res.json()` works
const StoreSchema = new Schema({
name: String
}, { toJSON: { virtuals: true } });
Okay, this is how you define a dependancy:
var mongoose = require('mongoose');
module.exports = mongoose.model('Todo', {
name : String,
itemsinstore: [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
And make sure you have different names:
var mongoose = require('mongoose');
module.exports = mongoose.model('Item', {
name : String,
storeforitem: [String]
});
Keep an eye on Item in both cases.
And then you just want to pass the array of ObjectIDs in it. See more here: http://mongoosejs.com/docs/populate.html
Try this:
Store.findOne({_id:'5892b603986f7a419c1add07'})
.exec (function(err, store){
if(err) return res.send(err);
var item = new Item({name: 'Foo'});
item.save(function(err) {
store.itemsInStore.push(item);
store.save(function(err) {
// todo
});
});

Packing data with mongoose

I have 3 files with different schema. User has many notebooks and notebooks has many notes. Example of schemas :
UserSchema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var User = new Schema({
username: { type: String, require: true, index: { unique: true }, trim: true},
password: { type: String, require: true, select: true },
age: { type: Number, min: 0 },
firstname: String,
secondname: String,
token: String,
role: String,
city: String,
rememberMe: Boolean
});
module.exports = mongoose.model('User', User);
NotebookSchema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
Note = require('./note'),
User = require('./user');
var NoteBook = new Schema({
creator: { type:Schema.ObjectId, ref:"User"},
name: String,
description: String
});
NoteBook.methods.getAllNotes = function(cb) {
Note.find({notebook: this}, function(err, noteList){
cb(noteList);
});
};
module.exports = mongoose.model('NoteBook', NoteBook);
NoteSchema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var NoteSchema = new Schema({
notebook: { type: Schema.Types.ObjectId, ref: 'NoteBook'},
name: String,
description: String,
content: String
});
module.exports = mongoose.model('Note', NoteSchema);
I get in request userId and I need to pack json all this line of data. User with Notebooks and Notebooks with note in one json. I triyed something like this:
function getTree(req, res) {
var data = [];
User.findOne({_id: req.body.userId}, function(err, user) {
NoteBook.find({creator: user._id}, function(err, notebookList) {
for (var idx in notebookList) {
Note.find({notebok: notebookList[idx]._id}, function(err, noteList) {
var children = [];
for (var noteIdx in noteList) {
children.push({
'text': noteList[idx].name,
'a_attr' : {
'data-node-type': 'note',
'data-node-id': noteList[idx]._id,
},
});
}
data.push({
'text': notebookList[idx].name,
'a_attr' : {
'data-node-type': 'notebook',
'data-node-id': notebookList[idx]._id,
},
'children': children
});
});
}
res.json({ tree: data });
});
});
}
but it doesn't work.
var async = require("async");
function getTree(req, res) {
var data = [];
User.findOne({_id: req.body.userId}, function(err, user) {
NoteBook.find({creator: user._id}, function(err, notebookList) {
async.forEach(notebookList, function(notebook, callback){
Note.find({notebok: notebook._id}, function(err, noteList) {
var children = [];
for (var noteIdx in noteList) {
children.push({
'text': noteList[idx].name,
'a_attr' : {
'data-node-type': 'note',
'data-node-id': noteList[idx]._id,
},
});
}
data.push({
'text': notebookList[idx].name,
'a_attr' : {
'data-node-type': 'notebook',
'data-node-id': notebook._id,
},
'children': children
});
});
}, function(err){
res.json({ tree: data });
});
});
});
}

cant get data from database after multiple schema declared (mongoose + express + mongodb

I'm new to node.js and I am having problem accessing to the when multiple mongoose schema were declare.
//schema.js in model
var mongoose = require('mongoose');
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
//User Schema
var userSchema = new Schema({
id: ObjectId,
firstname: {type: String, require: true},
lastname: {type: String, require: true},
username: {type: String, unique: true, require: true},
password: {type: String, require: true},
role: {type: [String], require: true}
})
var User = mongoose.model('User', userSchema);
module.exports = User;
//Question Schema
var qnSchema = new Schema({
id: ObjectId,
question: {type: String, require: true},
module_id: {type: ObjectId, ref: 'Module'}
})
var Question = mongoose.model('Question', qnSchema);
module.exports = Question;
//Answer Schema
var ansSchema = new Schema({
id: ObjectId,
answer: String,
question: {type: ObjectId, ref: 'Question'}
})
var Answer = mongoose.model('Answer', ansSchema);
module.exports = Answer;
//Module Schema
var modSchema = new Schema({
id: ObjectId,
name: {type: String, require: true}
})
var Module = mongoose.model('Module', modSchema);
module.exports = Module;
//Role Schema
var roleSchema = new Schema({
id: ObjectId,
role: {type: String, require: true}
})
var Role = mongoose.model('Role', roleSchema);
module.exports = Role;
//index.js in controller
var mongoose = require('mongoose');
var User = require('../models/schema');
var db = mongoose.connect('mongodb://localhost/damai');
module.exports = function(app) {
app.get('/', function(req, res) {
if (typeof req.session.userid == 'undefined') {
res.render('login', { title: app.get('title') });
} else {
res.render('index', { title: app.get('title') });
}
});
app.post('/login', function(req, res) {
passwordVerification(req, res);
});
}
function passwordVerification(req, res)
{
var userid = req.param('userid');
var password = req.param('password');
User.findOne({'username': userid},{'password': 1}, function(err, cb)
{
console.log(cb);
if(cb!= null)
{
if (password == cb.password) {
req.session.userid = userid;
res.render('index', { title: app.get('title'), 'userid': userid });
} else {
res.render('login', { title: app.get('title'), error: 'Invalid login'});
}
}
else
{
res.render('login', { title: app.get('title'), error: 'Invalid login'});
}
});
}
When I only have the "User Schema" in my schema.js, the database call from method "passwordVerification()" from index.js will return me the relevant password that was retrieve from the database. However, when I start adding in other schema such as "Question Schema" in schema.js, the method "passwordVerification()" will always return null.
When exporting multiple models from a single file like you are in schema.js, you need to give each exported model its own exports field name.
For example, replace the multiple module.exports = ... lines in schema.js with this code at the end of the file that exports all models:
module.exports = {
User: User,
Question: Question,
Answer: Answer,
Module: Module,
Role: Role
};
And then in index.js you can access the models like so:
var models = require('./schema');
...
models.User.findOne(...

Resources