Why is my createIndex in Mongoose failing? - node.js

In my cart controller I have the following segments of code:
const Cart = require('mongoose').model('Cart');
This works:
cart = await Cart.findOne({email:email});
But creating an index fails:
await Cart.createIndex({email: 1});
I get the following error:
car.controller#getCart TypeError: Cart.createIndex is not a function
at exports.getCart (backend\app\controllers\cart.controller.js:49:20)
at Layer.handle [as handle_request] (node_modules\express\lib\router\layer.js:95:5)
at next (node_modules\express\lib\router\route.js:137:13)
at exports.authenticate (backend\app\controllers\user.controller.js:42:13)

The literature says: createIndex() but createIndexes (plural) works;

This issue because Mongoose's model (in this case is Cart) haven't function createIndex() so you should change createIndex() to createIndexes().
You can see docs here: https://mongoosejs.com/docs/api.html#model_Model.createIndexes

Related

Error after upgrading Joi to latest version - Schema can only contain plain objects (name)

After upgrading Joi to the latest version #hapi/Joi(17.1.1) my server is not staring I am getting below error on startup. Seems there were some breaking changes in recent versions. Not able to get any clue yet, any help is appreciated.
Error: Schema can only contain plain objects (name)
at new module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/error.js:23:19)
at module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/assert.js:20:11)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:88:5)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at internals.Base.$_compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/base.js:631:24)
at /Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:92
at Object.exports.tryWithPath (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/common.js:173:16)
at internals.Base.method [as keys] (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:32)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:90:25)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:117:24)
at Object.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/index.js:123:24)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/validation.js:49:22)
at module.exports.internals.Route._setupValidation (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:197:43)
at new module.exports.internals.Route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:122:14)
at internals.Server._addRoute (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:498:23)
at internals.Server.route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:491:22)
at /Users/xyz/project/projectxyz/src/app.js:73:14
at Array.forEach (<anonymous>)
at init (/Users/xyz/project/projectxyz/src/app.js:72:17)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at process.runNextTicks [as _tickCallback] (internal/process/task_queues.js:66:3) {
path: 'name'
} Server Init error Error: Schema can only contain plain objects (name)
at new module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/error.js:23:19)
at module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/assert.js:20:11)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:88:5)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at internals.Base.$_compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/base.js:631:24)
at /Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:92
at Object.exports.tryWithPath (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/common.js:173:16)
at internals.Base.method [as keys] (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:32)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:90:25)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:117:24)
at Object.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/index.js:123:24)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/validation.js:49:22)
at module.exports.internals.Route._setupValidation (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:197:43)
at new module.exports.internals.Route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:122:14)
at internals.Server._addRoute (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:498:23)
at internals.Server.route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:491:22)
at /Users/xyz/project/projectxyz/src/app.js:73:14
at Array.forEach (<anonymous>)
at init (/Users/xyz/project/projectxyz/src/app.js:72:17)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at process.runNextTicks [as _tickCallback] (internal/process/task_queues.js:66:3) {
path: 'name'
}
To anyone who finds themselves in this dark place again, for me it was an issue when extending a Joi schema using the spread operator:
joi.object().keys({
...otherSchema,
position: joi.number()
})
This was causing the "Schema can only contain plain objects" error when I upgraded to Joi 17.5.0. Using the keys() syntax got around it:
otherSchema.keys({
position: joi.number()
})
Thanks all for your comments. I was able to resolve it after going through Joi's release notes.
The problem was due to the mix of Joi versions. In my codebase older version of Joi was used which was causing this. Below Github issue helped me realizing the issue.
https://github.com/hapijs/joi/issues/1913
i think u should do some thing like this to handle this error:
var ObjectJoi = Joi.object({
//some item that you want to add
})
var mySchema = new Schema(Joigoose.convert(ObjectJoi))
const myModel = mongoose.model('myModel', mySchema);
It's hard to tell without seeing the code.
But I faced the same issue when using Joi.extend().
const extendedType = Joi.extend(Joi => {
return {
type: 'myType', // <- PAY ATTENTION
base: Joi.array(),
messages: {
'stringArray:base': '...'
},
validate(value, helpers) {
...
},
coerce(value, helpers) {
...
}
}
});
The problem was that I used extendedType like below by mistake:
Joi.object({
someKey: extendedType,
...
});
instead of:
Joi.object({
someKey: extendedType.myType(),
...
});

Prevent Mongoose stack trace for errors

Mongoose emits a stack trace for a cast error. I know how to prevent the Mongoose error - please do not answer how to prevent the error.
How can I stop Mongoose emitting stack trace errors in production?
Error: Argument passed in must be a single String of 12 bytes or a
string of 24 hex characters at new ObjectID
(c:\proj\fboapp\node_modules\mongoose\node_modules\bson\lib\bson\objectid.js:38:11)
at c:\proj\fboapp\routes\user\no_auth_user_api_routes.js:135:27 at
Layer.handle [as handle_request]
(c:\proj\fboapp\node_modules\express\lib\router\layer.js:95:5) at
next (c:\proj\fboapp\node_modules\express\lib\router\route.js:131:13)
at Route.dispatch
(c:\proj\fboapp\node_modules\express\lib\router\route.js:112:3) at
Layer.handle [as handle_request]
(c:\proj\fboapp\node_modules\express\lib\router\layer.js:95:5) at
c:\proj\fboapp\node_modules\express\lib\router\index.js:277:22 at
Function.process_params
(c:\proj\fboapp\node_modules\express\lib\router\index.js:330:12) at
next (c:\proj\fboapp\node_modules\express\lib\router\index.js:271:10)
at Function.handle
(c:\proj\fboapp\node_modules\express\lib\router\index.js:176:3) at
router (c:\proj\fboapp\node_modules\express\lib\router\index.js:46:12)
at Layer.handle [as handle_request]
(c:\proj\fboapp\node_modules\express\lib\router\layer.js:95:5) at
trim_prefix
(c:\proj\fboapp\node_modules\express\lib\router\index.js:312:13) at
c:\proj\fboapp\node_modules\express\lib\router\index.js:280:7 at
Function.process_params
(c:\proj\fboapp\node_modules\express\lib\router\index.js:330:12) at
next (c:\proj\fboapp\node_modules\express\lib\router\index.js:271:10)
Nodejs v0.12.3
Mongoose v4.4.3
Generally speaking, add try-catch block in the codes could be correct way to do it.
Here are my test codes without try-catch block in codes, then prevent stack trace. Refer to this module mongoose disable stack trace, also add some new errors are added into mongoose, and set Error.stackTraceLimit to 0 will disable stack trace collection.
index.js
const captureStackTrace = Error.captureStackTrace;
const CastError = module.parent.require('mongoose/lib/error/cast');
const VersionError = module.parent.require('mongoose/lib/error/version');
const ValidatorError = module.parent.require('mongoose/lib/error/validator');
const ValidationError = module.parent.require('mongoose/lib/error/validation');
const OverwriteModelError = module.parent.require('mongoose/lib/error/overwriteModel');
const MissingSchemaError = module.parent.require('mongoose/lib/error/missingSchema');
const DivergentArrayError = module.parent.require('mongoose/lib/error/divergentArray');
Error.captureStackTrace = function( that, params) {
if(that instanceof CastError ||
that instanceof VersionError ||
that instanceof ValidatorError ||
that instanceof ValidationError ||
that instanceof OverwriteModelError ||
that instanceof MissingSchemaError ||
that instanceof DivergentArrayError) {
Error.stackTraceLimit = 0;
} else if (typeof that !== 'undefined'){
captureStackTrace.apply(Error, arguments);
}
}
Error.captureStackTrace(new VersionError);
app.js
require('mongoose-disable-stack-trace');
var f = Foo({_id: new ObjectId('adss112'), key: '123'}); // invalid ObjectId
Output:
Error: Argument passed in must be a single String of 12 bytes or a string of 24
hex characters
c:\share\node\node_modules\mongoose\node_modules\mongodb\lib\server.js:283
process.nextTick(function() { throw err; }) ^
Error: Argument passed in must be a single String of 12 bytes or a string of 24
hex characters
I was confused about why errors were being rendered to the browser without an error handler, until I read the ExpressJS error handling documentation page.
Apparently there is a default error handler which is triggered when no error handler is specified.
Express comes with an in-built error handler, which takes care of any
errors that might be encountered in the app. This default
error-handling middleware function is added at the end of the
middleware function stack.
The best practice is to specify a custom error handler for production which does not output the stack trace to the browser. The default error handler always outputs the stack trace to the browser.
There is no need for try-catch blocks to route uncaught errors to the custom error handler, because Express will automatically route uncaught errors to the error handler. Also note: error handler middleware MUST specify all 4 arguments: err, req, res and next
An example of a custom error handler:
app.use(function(err, req, res, next) {
res.send('uncaught error in production');
});

Bluebird warning "A promise was created in a handler but was not returned from it"

I get the warning about not returning a created promise from Bluebird and I do not understand why and how I should rewrite my code.
(I have tried reading about the warning at Bluebird API page and the anti-pattern page as I suspect this is what I'm doing)
In my view.js file:
var express = require('express'),
router = express.Router(),
settings = myReq('config/settings'),
Sets = myReq('lib/Sets'),
log = myReq('lib/utils').getLogger('View');
router.get('/:setId/', function(req, res, next) {
var
setId = req.params.setId,
user = req.user,
set = new Sets(setId, user);
log.info('Got a request for set: ' + setId);
// The below line gives the warning mentioned
set.getSet().then(function(output) {
res.send(output);
}).error(function(e){
log.error(e.message, e.data);
res.send('An error occurred while handling set:' + e.message);
});
});
module.exports = router;
In my Sets.js file I have:
var
Promise = require('bluebird'),
OE = Promise.OperationalError,
settings = myReq('config/settings'),
UserData = myReq('lib/userData'),
log = myReq('lib/utils').getLogger('sets'),
errorToSend = false;
module.exports = function(setId, user) {
var
sets = myReq('lib/utils').getDb('sets');
return {
getSet : function() {
log.debug('Getting set')
return sets.findOneAsync({
setId:setId
}).then(function(set){
if ( set ) {
log.debug('got set from DB');
} else {
set = getStaticSet(setId);
if ( ! set ) {
throw new OE('Failed getting db records or static template for set: ' + setId );
}
log.debug('got static set');
}
log.debug('I am handling set')
if ( ! checkSet(set) ) {
var e = new OE('Failed checking set');
e.data = set;
throw e;
}
return {
view : getView(set),
logic : set.logic,
canEdit : true,
error : errorToSend
};
});
}
};
};
So the line in my view.js file with "set.getSet()" gives the warning about not returning the created promise. It seems like this script still does what I expect it to do, but I do not understand why I get the warning.
Stacktrace:
Warning: a promise was created in a handler but was not returned from it
at Object.getSet (C:\dev\infoscrn\lib\Sets.js:36:25)
at C:\dev\infoscrn\routes\view.js:39:20
at Layer.handle [as handle_request] (C:\dev\infoscrn\node_modules\express\lib\router\layer.js:82:5)
at next (C:\dev\infoscrn\node_modules\express\lib\router\route.js:110:13)
at Route.dispatch (C:\dev\infoscrn\node_modules\express\lib\router\route.js:91:3)
at Layer.handle [as handle_request] (C:\dev\infoscrn\node_modules\express\lib\router\layer.js:82:5)
at C:\dev\infoscrn\node_modules\express\lib\router\index.js:267:22
at param (C:\dev\infoscrn\node_modules\express\lib\router\index.js:340:14)
at param (C:\dev\infoscrn\node_modules\express\lib\router\index.js:356:14)
at Function.proto.process_params (C:\dev\infoscrn\node_modules\express\lib\router\index.js:400:3)
at next (C:\dev\infoscrn\node_modules\express\lib\router\index.js:261:10)
at Function.proto.handle (C:\dev\infoscrn\node_modules\express\lib\router\index.js:166:3)
at router (C:\dev\infoscrn\node_modules\express\lib\router\index.js:35:12)
at Layer.handle [as handle_request] (C:\dev\infoscrn\node_modules\express\lib\router\layer.js:82:5)
at trim_prefix (C:\dev\infoscrn\node_modules\express\lib\router\index.js:302:13)
at C:\dev\infoscrn\node_modules\express\lib\router\index.js:270:7
at Function.proto.process_params (C:\dev\infoscrn\node_modules\express\lib\router\index.js:321:12)
at next (C:\dev\infoscrn\node_modules\express\lib\router\index.js:261:10)
at C:\dev\infoscrn\node_modules\express\lib\router\index.js:603:15
at next (C:\dev\infoscrn\node_modules\express\lib\router\index.js:246:14)
First, try and update all your dependencies. There's been a recent version of Bluebird, which fixed an issue involving this warning.
Next, make sure you return from all your handlers.
Then, if you still get the warning (like I do) you can disable this specific warning. I chose to do so by setting BLUEBIRD_W_FORGOTTEN_RETURN=0 in my environment.
Don't disable warnings. They're there for a reason.
The typical pattern is that if your onfulfill or onreject handler causes a Promise to be constructed, it will return that Promise (or some chain derived from it) from the handler, so that the chain adopts the state of that Promise.
So Bluebird is keeping track of when it is running one of your handler functions, and also keeping track of when it's Promise constructor is called. If it determines that a Promise was created at any point while your handler is running (that includes anywhere down in the callstack), but that Promise was not returned from your handler, it issues this warning because it thinks you probably forgot to write the return statement.
So if you legitimately don't care about the Promise that was created inside the handler, all you have to do is explicitly return something from your handler. If you don't care about what is returned from your handler (i.e., if you don't care what value the Promise fulfills with), then simply return null. Whatever you return, the explicit return (specifically, a return value other than undefined) tells Bluebird that you think you know what you're doing, and it won't issue this warning.
Make sure that every place you have return statement which is the solution works for me.

res.render causes native err after call to fs.stat / fs.access

I'm trying to build a catch-all route for a subset of my site that contains multiple directories/pages that need to be processed by ejs, but don't need specific routes.
[N.B., I included the sync version in the example below to remove any question of timing... the analogous implementation of fs.stat (and of fs.access) results in the same behavior]
router.get('/foobar/:page(*)', function(req, res, next) {
var fs = require('fs');
var path = require('path');
var viewsPath = req.app.get('views');
try
{
// see if there's an ejs file corresponding to request
var stats = fs.statSync(path.join(viewsPath, 'foobar', req.params.page + '.ejs'));
console.log(stats); // stats object seems accurate
// THROWS WHEN CALLING openSync
res.render('foobar/' + req.params.page, {title: 'foo'});
}
catch (e)
{
var err = new Error();
err.status = 404;
next(err);
}
}
The 404 path works just fine, but when I request a page that actually exists, the render call throws:
Unexpected error code undefined has occurred. Please retry your request
at Error (native)
at Object.fs.openSync (fs.js:500:18)
at Object.fs.readFileSync (fs.js:352:15)
at includeSource (C:\Users\Jim\Documents\myProject\node_modules\ejs\lib\ejs.js:194:17)
at C:\Users\Jim\Documents\myProject\node_modules\ejs\lib\ejs.js:528:26
at Array.forEach (native)
at Object.Template.generateSource (C:\Users\Jim\Documents\myProject\node_modules\ejs\lib\ejs.js:505:15)
at Object.Template.compile (C:\Users\Jim\Documents\myProject\node_modules\ejs\lib\ejs.js:427:12)
at Object.compile (C:\Users\Jim\Documents\myProject\node_modules\ejs\lib\ejs.js:288:16)
at handleCache (C:\Users\Jim\Documents\myProject\node_modules\ejs\lib\ejs.js:147:16)
at View.exports.renderFile [as engine] (C:\Users\Jim\Documents\myProject\node_modules\ejs\lib\ejs.js:350:14)
at View.render (C:\Users\Jim\Documents\myProject\node_modules\express\lib\view.js:126:8)
at tryRender (C:\Users\Jim\Documents\myProject\node_modules\express\lib\application.js:639:10)
at EventEmitter.render (C:\Users\Jim\Documents\myProject\node_modules\express\lib\application.js:591:3)
at ServerResponse.render (C:\Users\Jim\Documents\myProject\node_modules\express\lib\response.js:961:7)
at C:\Users\Jim\Documents\myProject\routes\power-essentials.js:32:7
at Layer.handle [as handle_request] (C:\Users\Jim\Documents\myProject\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\Jim\Documents\myProject\node_modules\express\lib\router\route.js:131:13)
at Route.dispatch (C:\Users\Jim\Documents\myProject\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\Jim\Documents\myProject\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\Jim\Documents\myProject\node_modules\express\lib\router\index.js:277:22
at param (C:\Users\Jim\Documents\myProject\node_modules\express\lib\router\index.js:349:14)
It's behaving almost like the fs.statSync call has placed a lock on the file that render chokes on when trying to open the view file.
occams razor: the test page I was working with had an invalid include path reference within it! It wasn't complaining about the template I was trying to load, but rather one referenced within it.

Sequelize with postgres defaults to mysql

I'm setting up Sequelize to manage postgres in a Node.js app.
I've required sequelize-postgres, as well as declared 'postgres' in the dialect attr when instantiating a new Sequelize object. But for some reason, it defaults to using mysql.
Exact error message:
/Users/...project/node_modules/sequelize/lib/dialects/mysql/connector-manager.js:306
var connection = mysql.createConnection(connectionConfig);
^
TypeError: Cannot call method 'createConnection' of undefined
at module.exports.connect (.../node_modules/sequelize/lib/dialects/mysql/connector-manager.js:306:28)
at Object.pool.Pooling.Pool.create
(.../node_modules/sequelize/lib/dialects/mysql/connector-manager.js:131:19)
at createResource (.../node_modules/sequelize/node_modules/generic-pool/lib/generic-pool.js:258:13)
at dispense (.../node_modules/sequelize/node_modules/generic-pool/lib/generic-pool.js:250:9)
at Object.me.acquire (.../node_modules/sequelize/node_modules/generic-pool/lib/generic-pool.js:316:5)
at null.fct (.../node_modules/sequelize/lib/dialects/mysql/connector-manager.js:241:19)
at null.<anonymous> (.../node_modules/sequelize/lib/emitters/custom-event-emitter.js:24:18)
at processImmediate [as _immediateCallback] (timers.js:336:15)
Any help is appreciated thank you!

Resources