How to register mongoose plugin for all schemas? - node.js

What am I missing? The Mongoose docs say that mongoose.plugin() registers a plugin for all schemas. This is not working. I CAN register my plugin on EACH schema.
My plugin:
module.exports = function (schema, options) {
schema.set('toObject',{
transform: function (doc, ret, options) {
return {
test: 'It worked!'
};
}
});
};
My schema:
var testPlugin = require('test-plugin.js');
var personSchema = mongoose.Schema({
_id : { type: String, default: $.uuid.init },
ssn : { type: String, required: true, trim: true },
first : { type: String, required: true, trim: true },
middle : { type: String, required: true, trim: true },
last : { type: String, required: true, trim: true }
});
personSchema.plugin(testPlugin);
var model = mongoose.model('Person', personSchema);
module.exports = model;
The code above works, unfortunately. However, the following code does not:
var personSchema = mongoose.Schema({
_id : { type: String, default: $.uuid.init },
ssn : { type: String, required: true, trim: true },
first : { type: String, required: true, trim: true },
middle : { type: String, required: true, trim: true },
last : { type: String, required: true, trim: true }
});
var model = mongoose.model('Person', personSchema);
module.exports = model;
My test app:
var testPlugin = require('test-plugin.js');
mongoose.plugin(testPlugin);
mongoose.Promise = global.Promise;
mongoose.connect(config.db);
mongoose.connection.on('error', function (err) {
if (err) { throw err; }
});
mongoose.connection.once('open', function (err) {
if (err) { throw err; }
seeds.doSeed(function(err){
if (err) { return process.exit(1); }
models.Person.find({}, function(err, people){
if (err) { throw err; }
var person = people[0];
var oPerson = person.toObject();
console.log(JSON.stringify(oPerson));
});
});
});
I've tried moving the mongoose.plugin(testPlugin) all over the app.js file... after the connect, etc... and nothing has worked.

Plugins might not be registered with mongoose.plugin(myMongoosePlugin) because mongoose models were created before you are registering plugins globally.
In case if you have expressjs routes:
Make sure that in your app.js (server.js) you are registering mongoose plugins before you are registering/creating expressjs routes (which are using mongoose models to communicate with database).
Example:
in app.js
const express = require(express);
const mongoose = require('mongoose');
const myMongoosePlugin = require('<Mongoose Plugin file path>');
mongoose.plugin(myMongoosePlugin);
let app = express();
//register expressjs routes
require('<Express routes file path>')(app, express.Router());
// or create expressjs routes
app.post('/person', (req, res, next) => {
//where someMethod is using person mongoose model
this.someController.someMethod(someArguments)
.then((user) => {
res.json(user);
}).catch((error) => {
next(error);
});
});
// ... Some other code ...
mongoose.connect(<databaseConnectionString>);
app.listen(<Port>);

Try requiring your model also in your app.js file. Somewhere after mongoose.plugin(testPlugin).

This is not the best solution but work , you must define your Schema in each file and then export that
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({ ... })
module.exports = UserSchema;
and then you should implement just one file for setup your models , for example
const mongoose = require('mongoose');
// import all of your schemas
const userSchema = require(./user/modelSchema);
const TicketSchema = require(./Ticket/modelSchema);
// *** implement your (Global Plugin) here ***
mongoose.plugin(myPlugin);
// define and create all of your models
const User = mongoose.model('User', userSchema);
const Ticket = mongoose.model('Ticket', TicketSchema);
module.exports = {
userModle: User,
ticketModel: Ticket,
}

This is just another view of what #Andrei Surzhan already stated.
The key here is to Apply the plugins before the Routes.
I recently got this issue, where the plugin's didn't work on a Global scale but it did when added them individually on the creation of their Schema.
For reference, my project is structured this way.
// server.js file
require('dotenv').config();
const http = require('http');
const mongoose = require('mongoose');
const myPlugin = require('path-to-my-plugin');
mongoose.plugin(myPlugin);
const app = require('./app');
const PORT = process.env.PORT || 8000;
const server = http.createServer(app);
// MONGO CONNECTION
mongoose.connect(process.env.MONGODB_URI);
mongoose.connection.on('open', () => console.log('MongoDB connection ready!'));
mongoose.connection.on('error', console.error);
server.listen(PORT, console.log(`Listening on PORT ${PORT}`));
// app.js file
const express = require('express');
// Routes
const clientsRouter = require('./routes/clients/clients.router');
const paymentsRouter = require('./routes/payments/payments.router');
const app = express();
// Parse incoming requests with JSON payloads
app.use(express.json());
// Parse incoming requests with Form payloads
app.use(
express.urlencoded({
extended: false,
})
);
app.use('/clients', clientsRouter);
app.use('/payments', paymentsRouter);
module.exports = app;
As you can see at server.js we add the plugin before even importing app.js this is because when we import app.js we will call the routes and the plugin will not be passed.
Another way to do it, is adding the plugin on each Schema.
Example
// clients.model.js
const mongoose = require('mongoose');
const myPlugin = require('path-to-my-plugin');
const clientSchema = new mongoose.Schema({ ... });
clientSchema.plugin(myPlugin);
module.exports = mongoose.model('Client', clientSchema);

Related

Getting a typeerror: cannot read property find of undefined

I have copied the code from another application, and that is working fine. but this one is giving me a Typeerror: cannot read property find of undefined when I am making the request to the database using the api.
here is my server.js
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
const mongoose = require("mongoose");
const userRoutes = express.Router();
const PORT = 4000;
let { User } = require("./models/User");
app.use(cors());
app.use(bodyParser.json());
mongoose.connect("mongodb://127.0.0.1:27017/school", { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once("open", function() {
console.log("MongoDB database connection established successfully");
});
userRoutes.route("/").get(function(req, res) {
User.find(function(err, users) {
if (err) {
console.log(err);
} else {
res.json(users);
}
});
});
app.use("/users", userRoutes);
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
here is my User Model:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
let User = new Schema({
firstName: {
type: String,
required: "First name is required"
},
lastName: {
type: String,
required: "Last name is required"
},
emailAddress: {
type: String,
required: "Email address is required",
match: [
/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
"A valid email address is required"
]
},
password: {
type: String,
required: "Password is required"
}
});
module.exports = mongoose.model("User", User);
Your problem is the wrong way of importing User Schema , you can fix it like so :
let User = require("./models/User");
now your functions will work fine :)

TypeError: Cannot read property 'comment_text' of undefined

I've declared a file called commentSchema which has some fields:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const moment = require('moment');
var commentSchema = new Schema ({
comment_text: {type: String, required: true},
user_token: {type: String, required: true},
activity_id: { type: Schema.ObjectId, ref: 'Activity', required: true },
is_hidden: { type: Boolean, "default": false },
created_at: { type: Number, "default": moment().unix() },
updated_at: { type: Number, "default": moment().unix() }
})
module.exports = mongoose.model('Comment', commentSchema);
and this is my router file:
var Router = require('router');
var router = Router();
var express = require('express');
var app = express();
// importing Models
var userSchema = require('./models/userSchema.js');
var activitySchema = require('./models/activitySchema.js');
var commentSchema = require('./models/commentSchema');
// Parsing the informations get from the client
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
router.get('/comments', (req, res) => {
});
router.post('/comment', (req, res) => {
var newComment = {
comment_text: req.body.comment_text,
user_token: req.body.user_token,
activity_id: req.body.activity_id
}
console.log(newComment);
commentSchema.create(newComment, (err) => {
if (err){
console.log(err);
}
else{
console.log('DONE!');
}
})
})
module.exports = router;
I'm trying to send post request using POSTMAN but I get the following error:
Cannot read property 'comment_text' of undefined
From the documentation of router. It says you have to use following:
router.use(bodyParser.json())

Mongoose populate find array of ObjectId

I'm trying to populate an array of ObjectIds when doing a find with Mongoose.
Here is the models/comment.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// set up a mongoose model
var CommentSchema = new Schema({
comment: {
type: String,
unique: false,
required: true
},
date: {
type: Date,
default: new Date()
},
});
module.exports = mongoose.model('Comment', CommentSchema);
Here is the models/question.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Comment = require('./comment');
// set up a mongoose model
var QuestionSchema = new Schema({
title: {
type: String,
unique: false,
required: true
},
question: {
type: String,
required: true
},
plus: {
type: Number,
required: true,
default: 0
},
minus: {
type: Number,
required: true,
default: 0
},
date: {
type: Date,
default: new Date()
},
comments:[
{type: Schema.Types.ObjectId, ref: 'Comment'}
]
});
module.exports = mongoose.model('Question', QuestionSchema);
Here is index.js
var express = require('express');
var app = express();
var request = require('request-promise');
var bodyParser = require('body-parser');
var morgan = require('morgan');
var mongoose = require('mongoose');
var passport = require('passport');
var config = require('./config/database'); // get db config file
var User = require('./models/user'); // get the mongoose model
var Room = require('./models/room'); // get the mongoose model
var Comment = require('./models/comment'); // get the mongoose model
var Question = require('./models/question'); // get the mongoose model
var port = process.env.PORT || 5000;
var jwt = require('jwt-simple');
var http = require('http');
var io = require('socket.io');
var server = http.createServer(app);
var io = io.listen(server);
// get our request parameters
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// log to console
app.use(morgan('dev'));
// Use the passport package in our application
app.use(passport.initialize());
// Set the port
app.set('port', port);
//App files located in /public
app.use(express.static(__dirname + '/public'));
// views is the directory for all template files
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// The root url of the website serves the Angular app
app.get('/', function (request, response) {
response.render('pages/index');
});
// connect to database
mongoose.connect(config.database);
// pass passport for configuration
require('./config/passport')(passport);
var roomService = require('./controllers/roomservice.js');
roomService.setup(io);
// connect the api routes under /api/*
app.use('/api', apiRoutes);
// Start the Express app
server.listen(app.get('port'), function () {
console.log('Node app is running on port', app.get('port'));
});
Here is controllers/roomservice.js
function RoomService(){
var socketio;
var Comment = require('../models/comment'); // get the mongoose model
var Question = require('../models/question'); // get the mongoose model
var Room = require('../models/room'); // get the mongoose model
function setup(io){
socketio = io;
socketio.on("connection", function(socket){
socket.on('joinRoom', function(msg){
console.log("joinRoom");
socket.join(msg.room)
Question.find({})
.exec(function(err, questions) {
for(var question in questions){
for(var comment in questions[question].comments){
questions[question].comments[comment] = Comment.find({ "_id": questions[question].comments[comment]});
}
}
socket.emit("listQuestions", questions)
});
});
socket.on('addQuestion', function(msg){
console.log("addQuestion");
var question = new Question({
title: msg.title,
question: msg.question
});
// save the question
question.save(function(err) {
if (err) throw err;
io.to(msg.room).emit("addQuestion", question);
});
});
socket.on('addComment', function(msg){
var comment = new Comment({
comment: msg.comment
});
// save the comment
Question.findOne({_id: msg.question}, function(err, question){
if (err) throw err;
question.comments.push(comment);
question.save(function(err) {
if (err) throw err;
io.to(msg.room).emit("addComment", comment);
console.log(question);
});
});
});
socket.on('addPlus', function(msg){
// save the comment
Question.findOne({_id: msg.question}, function(err, question){
if (err) throw err;
question.plus = question.plus + 1;
question.save(function(err) {
if (err) throw err;
io.to(msg.room).emit("addPlus", question);
});
});
});
socket.on('addMinus', function(msg){
// save the comment
Question.findOne({_id: msg.question}, function(err, question){
if (err) throw err;
question.minus = question.minus + 1;
question.save(function(err) {
if (err) throw err;
io.to(msg.room).emit("addMinus", question);
});
});
});
});
}
return{
setup: setup
}
}
module.exports = new RoomService();
I'm trying to populate the array of comments when returning the list of questions. I tried it with the populate method from Mongoose but it returns an empty array of comments.
Question.find({}).populate("comments")
.exec(function(err, questions) {
socket.emit("questions", questions)
});
When I don't put the populate method I get something like this :
[{"title": "test", "comments": ["1253454", "654654747"]},
{"title": "test", "comments": ["1253454", "654654747"]}]
But I want something like this :
[{"title": "test", "comments": [{"comment": "test"}, {"comment": "test2"}]},
{"title": "test", "comments": [{"comment": "test"}, {"comment": "test2"}]}]
What am I doing wrong?
What is your mongoose version? The version 4.7.1 is fine for me:
import { connDb } from './base';
import { model, Schema, SchemaTypes, disconnect } from 'mongoose';
const Question = model<any>('Question', new Schema({
title : SchemaTypes.String,
comments: [
{
type: SchemaTypes.ObjectId,
ref : 'Comment',
},
],
}))
const Comment = model<any>('Comment', new Schema({
comment: SchemaTypes.String,
}))
connDb().then(() => Promise.all([
Comment.remove({}),
Question.remove({}),
])).then(() => Comment.insertMany([
{
comment: 'hello',
},
{
comment: 'world',
}
])).then((data: any[]) => Question.insertMany([
{
title : 'question',
comments: data.map((item: any) => item._id),
}
])).then(() => Question.find({}).populate('comments').exec()).then((d) => {
console.log(JSON.stringify(d))
}).then(() => disconnect())
The result is:
+ ts-node ./src/__test__/pop_comment.ts
[{"_id":"5846322e69db6c1ec86ac5fd","__v":0,"title":"question","comments":[{"_id":"5846322e69db6c1ec86ac5fb","__v":0,"comment":"hello"},{"_id":"5846322e69db6c1ec86ac5fc","__v":0,"comment":"world"}]}]

Node.Js mongoose find not working

I'm trying to get the documents from my MongoDB by using mongoose "find" method. But I'm not able to get records. It did not returns any error. Here is my code
Server.js
var express = require('express');
var bodyparser = require('body-parser');
var mongoose = require('mongoose');
var cors = require('cors');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
mongoose.promise = global.promise;
mongoose.connect("mongodb://localhost:27017/testdb");
app.use(bodyparser.json());
app.use(cors());
app.use(express.static(__dirname + 'server'));
var api = require('./routes/apihandler')(app, express, io);
app.use('/alerts', api);
http.listen(3000, function(err){
if(err) {
console.log(err);
} else {
console.log('Listening PORT' + config.port);
}
});
apihandler.js
var request = require('request');
var express = require('express');
var alertRoutes = require('../../services/routes/alertRoutes');
var api = express.Router();
module.exports = function(app, express, io){
api.get('/getAllAlerts/:retailerId/:loyaltyId', getAllAlerts);
return api;
}
function getAllAlerts(req, res, callback) {
console.log('apihandler');
try {
alertRoutes.getAllAlerts(req,res,callback);
}
catch(err) {
res.send({"status" : "error", message: err.mes});
}
}
Manager.js
var alertModel = require('./../models/alertModel');
alertModel.find({}, function (err, docs) {
console.log(err);
console.log(docs);
});
Model.js
var mongoose = require('mongoose');
var alertSchema = new mongoose.Schema({
id:{ type: String },
alertType:{ type: Number},
retailerId: { type: String },
loyaltyId: { type: String },
email: { type: String },
description: { type: String},
locationId:{type: String },
reason:{type: String},
reasonDescription:{type: String},
capturedReasonsList:mongoose.Schema.Types.Mixed
},{ collection: 'alerts' });
module.exports = mongoose.model('alerts', alertSchema);
alertRoutes.js
//Get all Alerts
function getAllAlerts(req, res, callback){
console.log('getAllAlerts');
=
var srchData = {
retailerId:req.params.retailerId,
loyaltyId:req.params.loyaltyId
};
retailerId='+req.params.retailerId+'&loyaltyId='+req.params.loyaltyId;
alertManager.getAlert(srchData,function(err,alertDetails){
console.log('alertDetails',alertDetails);
if (err) throw err;
if(alertDetails && alertDetails.length > 0){
res.status(200).send(alertDetails);
}else{
res.status(200).send({success: false,message: 'Alert Details not Found'});
}
});
// });
}
I can able to get into Manager js. But the find query is not working
Please Help me to resolve this issue.
Thank you.
Try these codes. I am working with these codes & it works for me.
Model :
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var alertSchema = mongoose.Schema({
id:{ type: String },
alertType:{ type: Number},
retailerId: { type: String },
loyaltyId: { type: String },
email: { type: String },
description: { type: String},
locationId:{type: String },
reason:{type: String},
reasonDescription:{type: String},
capturedReasonsList:mongoose.Schema.Types.Mixed
});
mongoose.model('Alert',alertSchema);
Server Code :
var mongoose = require('mongoose');
var alertModel = mongoose.model('Alert');
alertModel.find().exec(function (err, docs) {
if(!err)
console.log(docs);
});
Maybe the find is just never called... Do some console.log before the find to make sure.
Provide the code of "getAlert", we cannot see where and how Manager.js is used.

Mongoose and node js - TypeError: object is not a function

The issue that it doesnt let me use the genre schema
i have 2 schemas user and genre
user schema works fine but the genre schema is undefind
user.js - schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Genre = require('../Models/genre');
// create a schema
var userSchema = new Schema({
name: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
age: String,
gender: String,
genres: [Genre.genreSchema]
});
// the schema is useless so far
// we need to create a model using it
var User = mongoose.model('User', userSchema);
// make this available to our users in our Node applications
module.exports = User;
genre.js - schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// create a schema
var genreSchema = new Schema({
name: { type: String, required: true, unique: true },
age: String,
gender: String
});
// the schema is useless so far
// we need to create a model using it
var Genre = mongoose.model('Genre', genreSchema);
// make this available to our genres in our Node applications
module.exports = Genre;
genre controller - router --- same as user router controller
var express = require('express');
var bodyParser = require('body-parser');
var Genre = require('../Models/genre');
// ROUTES FOR OUR API
// =============================================================================
var router = express.Router(); // get an instance of the express Router
// middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Something is happening.');
next(); // make sure we go to the next routes and don't stop here
});
router.route('/genres')
// create a genre
.post(function(req, res) {
console.log(Genre);
**//here is the error when trying to post new genre**
var Genre = new Genre(req.body); // create a new instance of the user model
// save the genre and check for errors
Genre.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Genre created!' });
});
})
// get all the genres
.get(function(req, res) {
Genre.find(function(err, genres) {
if (err)
res.send(err);
res.json(genres);
});
});
module.exports = router;
server.js - the app js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var userRouter = require('./Controllers/user');
var genreRouter = require('./Controllers/genre');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017'); // connect to our datababase
// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 8080; // set our port
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', userRouter);
app.use('/api', genreRouter);
// START THE SERVER
// =============================================================================
app.listen(port);
console.log('see whats happening on port ' + port);
why the model is undefind only when i post new genre? and for user it works fine?
is it the way to do schema whithin schema? or there is a better way?
i have try to use only the genre model with out the user and it still same error
i hope i am clear enough
thanks for the helpers
You shouldn't be using the same name for the schema and for the new Genre.
try changing it to
var newGenre = new Genre(req.body); // create a new instance of the user model
// save the genre and check for errors
newGre.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Genre created!' });
});

Resources