Mongoose Validate Foreign Key (ref) - node.js

I have tried several different ways to validate a foreign key in Mongoose and cannot figure it out.
I have a schema like this:
//Doctors.js
var schema = mongoose.Schema({
email: { type: String }
}
module.exports = mongoose.model('Doctors', schema);
//Patients.js
var Doctors = require('./Doctors');
var schema = mongoose.Schema({
email: { type: String },
doctor: { type: String, ref: 'Doctors' }
}
schema.pre('save', function (next, req) {
Doctors.findOne({email:req.body.email}, function (err, found) {
if (found) return next();
else return next(new Error({error:"not found"}));
});
});
module.exports = mongoose.model('Patients', schema);
however I get an this error: Uncaught TypeError: Object #<Object> has no method 'findOne'
Anyone know how to do something similar to what I am trying to do here?

I kept googling over the past hour, and saw something about scope that got me thinking. The following code fixed my problem.
//Doctors.js
var mongoose = require('mongoose');
var schema = mongoose.Schema({
email: { type: String }
}
module.exports = mongoose.model('Doctors', schema);
//Patients.js
//var Doctors = require('./Doctors'); --> delete this line
var mongoose = require('mongoose');
var schema = mongoose.Schema({
email: { type: String },
doctor: { type: String, ref: 'Doctors' }
}
schema.pre('save', function (next, req) {
var Doctors = mongoose.model('Doctors'); //--> add this line
Doctors.findOne({email:req.body.email}, function (err, found) {
if (found) return next();
else return next(new Error({error:"not found"}));
});
});
module.exports = mongoose.model('Patients', schema);
Although this was a quick fix, in no way was it an obvious fix (at least to me). The issue was the scope of variables.

Related

Await returning undefined into the async function (var all_courses is undefined)

I am trying to return the courses that belong to a certain program. for that I use the async / await but it is not returning the courses of the program that happened as id in the asynchronous function:
Program Controller
function getProgram(req, res){
var programId = req.params.id;
Program.findById({'_id': programId}, (err, program)=>{
if (err) return res.status(500).send({message: 'Petition failed'});
if (!program) return res.status(404).send({message: 'There is not program to show'});
getCoursesByProgram(programId).then((value) =>{
return res.status(200).send({
program,
all_courses: value.all_courses
});
});
});
}
async function getCoursesByProgram(program_id){
var all_courses = await Course.find({'program': program_id}).exec((err, courses)=>{
if(err) return handleError(err);
return courses;
});
return{
all_courses: all_courses
}
}
Models
'use strict'
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CourseSchema = Schema({
title: String,
video: String,
creator: {type: Schema.ObjectId, ref: 'User'},
program: {type: Schema.ObjectId, ref: 'Program'},
description: String,
created_at: String
});
module.exports = mongoose.model('Course', CourseSchema);
'use strict'
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProgramSchema = Schema({
title: String,
creator: {type: Schema.ObjectId, ref: 'User'},
image: String,
description: String,
created_at: String
});
module.exports = mongoose.model('Program', ProgramSchema);
Please somebody can help me with that?
When you pass a callback to .exec, it no longer returns a promise. Instead, you can do error / value handling using promises:
try {
return { all_courses: await Course.find({'program': program_id}).exec() };
} catch (err) {
return handleError(err);
}
Note that getCoursesByProgram will always resolve unless handleError throws an error.
getProgram can also be an async function. You can consolidate the error handling too, although if you want more generalized error handling you will have to either catch the errors independently or parse the error messages somehow.
async function getProgram(req, res) {
try {
const programId = req.params.id;
const program = await Program.findById({'_id': programId}).exec();
if (!program) return res.status(404).send(...);
const courses = await getCoursesByProgram(programId);
return res.status(200).send({
program,
all_courses: value.all_courses,
});
} catch (err) {
res.status(500).send({ message: 'Petition failed' });
}
}

Cascade Delete in mongo

I am new to MongoDB. I created 4 collections & they are connected with each other. (I am using node.js to write it)
Here, it's my question. How can I delete all records at once? Is there something like deep level population?
This one holds all models.
const DataModel = mongoose.Schema({
_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', require: true},
order: { type: mongoose.Schema.Types.ObjectId, ref: 'Order', require: true},
});
User model
const userSchema = mongoose.Schema({//other stuff});
Order model
const orderSchema = mongoose.Schema({
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
//other stuff
});
Product model
const productSchema = mongoose.Schema({//other stuff});
I can delete the entry with these code from the database, but the other entries still there
exports.delete_data = (req, res, next) => {
const id = req.params.userId;
userDataModel.deleteOne({_id: id})
.exec()
.then(docs => {
res.status(200).json({
message: 'Record Deleted',
request: {
type: 'POST'
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
Update: However, I wonder, Could I call other defined delete functions for order, product inside delete_data
As #Geert-Jan suggest, cascade delete is my solution. The link that geert-jan gave solve my problem. However, I wonder, Could I call other defined delete functions for order, product inside delete_data
i did this and it could be good for someone who wants to delete documents in cascade linked to any field of a model.
async blackHole() {
try {
const rtn = new ApiResponse<any>();
const userId = id;
const accountId = mongoose.Types.ObjectId(id);
var CollectionNames: any[] = [];
mongoose.connection.db.listCollections().toArray(function (err, collections) {
CollectionNames = collections.map(c => c.name);
CollectionNames.forEach((element: any) => {
mongoose.connection.db.collection(element).deleteMany({ "account": accountId });
});
});
const accountController = new AccountController(this.wsParams);
await accountController.delete(id)
await super.delete(userId);
return rtn;
} catch (error: any) {
const rtn = new ApiResponse<any>();
rtn.message = error;
rtn.success = false;
rtn.status = 422;
return rtn;
}
}
I hope you can use it :D

mongoose call model method from outside of express app

I have mongoose model file like this
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var testSchema = new Schema({
name: { type: String },
username: { type: String },
provider: { type: String },
accessToken: { type: String },
testId: { type: String }
});
/**Indexing*/
testSchema.index({ testId: 1, accessToken: 1 });
testSchema.statics = {
get: function (id, callback) {
this.findOne({'testId': id}, function(error, items){
callback(error, items);
});
},
create: function (data, callback) {
var test = new this(data);
test.save(callback);
}
};
var test = mongoose.model('test', testSchema);
/** export schema */
module.exports = {
Test: test
};
it is working Good with an express app. But I would like to use this model to view and insert data from command line. So, here is my approch which is not working
var Test = require('./app/model/test').Test;
Test.get({'testId': 1},function(err,res){
if(!err){
console.log(res);
}else{
console.log(err);
}
I see two problems:
you're not calling mongoose.connect() anywhere, so it's not connecting to the database
it looks like you should pass the id as an argument to get(); now you're passing it a query. Try this: Test.get('1', ...)

NodeJS/Mongoose: exports.function and module.exports incompatibility

This is my User.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var UserSchema = mongoose.Schema({
email: {
type: String,
unique: true
},
password: String,
});
var User = mongoose.model('User', UserSchema);
function createDefaultUsers() {
User.find({}).exec(function (err, collection) {
if (collection.length === 0) {
User.create({
email: 'name#eemail.com',
password: 'password0',
});
}
exports.createDefaultUsers = createDefaultUsers;
module.exports = mongoose.model('User', UserSchema);
I call createDefaultUsers in another file to create initial users.
But when this gives me the following error:
userModel.createDefaultUsers();
^ TypeError: Object function model(doc, fields, skipId) {
if (!(this instanceof model))
return new model(doc, fields, skipId);
Model.call(this, doc, fields, skipId); } has no method 'createDefaultUsers'
But if I comment out module.exports = mongoose.model('User', UserSchema); it compiles fine.
What am I doing wrong.
Cheers.
In this case, you should attach that function as a static method and export the model.
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var UserSchema = mongoose.Schema({
email: {
type: String,
unique: true
},
password: String,
});
UserSchema.statics.createDefaultUsers = function createDefaultUsers(cb) {
return User.find({}).exec(function (err, collection) {
if (collection.length === 0) {
User.create({
email: 'name#eemail.com',
password: 'password0',
}, cb);
} else {
if (cb) {
cb(err, collection);
}
}
});
};
var User = mongoose.model('User', UserSchema);
module.exports = User;
Now you can use it directly from the model (which is likely very similar to how you're already using it):
require('./models/user').createDefaultUsers();

mongoose (mongodb) return boolean query.exec?

I try to make a library for use in node.js with mongoose (mongoDB).
In my library, I want simply check if a user is_admin (group admin) or not.
Here is my model :
var mongoose = require('mongoose');
module.exports = mongoose.model('UsersGroups',{
user_id: String,
group_id: String
});
Here is my library :
var UsersGroups = require('../models/users_groups');
is_admin = function(userid)
{
console.log('USERID : '+userid);
var query = UsersGroups.find({'user_id': userid});
query.select('user_id');
query.where('group_id').equals('54d2264ed9b0eb887b7d7638');
return query.exec();
}
module.exports = is_admin;
I want to the query return true or false.
I call the library like this :
var is_admin = require('../library/mylib.js');
...
if (is_admin(group.user_id))
{
console.log('IS_ADMIN');
}
else
{
console.log('NOT_ADMIN');
}
Someone can coach me for this?
You can just run this query
UsersGroups.find({'user_id': userid, 'group_id': '54d2264ed9b0eb887b7d7638'}).count().exec();
it will find the matching pair - return 1 if it exists which is truthy in javascript. If it does not exist it will return 0 which is falsy so you will be able to use it inside if statements
query.exec() return Promise not Boolean
Using mongoose Schema and Model will give more nice feature;
Example User Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: { type: String, required: true, trim: true }
// set user types as enumeration
type: { type: String, enum: ["admin", "user", "guest"], required: ture, default: 'user' }
});
var User = mongoose.model('User', UserSchema);
User.prototype.isAdmin = function(){
return this.type === "admin";
}
module.exports = User;
On controller
var user = require('model/user');
user.findById("54d2264ed9b0eb887b7d7638", function(err, user){
if(err)
return console.error(err.stack);
if(!user)
return console.error("User not found!");
if(!user.isAdmin())
console.log("User is not admin");
else
console.log("User is admin");
});
If you want to check with user group, you can change isAdmin function as you want

Resources