Creating a mongoose Schema using a javascript object - node.js

This might seem like a really silly question, but is it possible to pass a js object instead of having to write the key value pairs during a Schema assignment?
So, instead of let schema = new mongoose.Schema({name: String}), can you say
const mongoose = require('mongoose')
let obj = {name: String}
let schema = new mongoose.Schema(obj)
Thanks!

Yes, you can pass the key: type pairs, validations etc in them as an object in the Schema. Basically, what it does, it passes the definition provided in the object to the schema constructor.
constructor(definition?: SchemaDefinition, options?: SchemaOptions);
But whenever you write as an object way, autocomplete and other types won't be available (IDE intellisense) and causes more error-prone code when you compile it and also there is no effect on the database by doing this way.

The answer is: You can't.
Because that's how Mongoose works. That's a framework with many rules that we have to obey in order to successfully leverage its functionalities.

Related

Why TypeOrm advises to create empty object via `new EntityClass()` THEN only pass fields value?

I'm using NestJS (not Next) NodeJS framework
When I'm creating new objects I used to use new OjbectClass({...fieldsValues});
It's great especially when you use transform pipes from class-transformer;
Besides this approach is used for entity creating:
https://docs.nestjs.com/techniques/database#separating-entity-definition
But as far I see in different guides of TypeOrm usage
here: https://typeorm.io/#/ ,
and here: https://orkhan.gitbook.io/typeorm/docs/entities .
They show first to create an empty object, then only set fields with values:
const object = new EntityObject();
object.field = 'value';
Why? Does it make sense?
Does NodeJS create a redundant hidden class of properties passed via object into Entity Class constructor? If yes - then we can pass coma-separated arguments
I believe it's just cause that's how the docs are. Looking at the code for BaseEntity it does not look like having a constructor to assign the fields would be a problem

What is the # for in the Mongoose API docs?

Sorry if this is a dumb question but I've been searching and can't find an answer. I'm new to Mongoose, and programming in general, and I've been reading the API docs to better understand what Mongoose can do. In the docs they have two ways of accessing an object property, through "dot" notation and through "#" notation? I'm not sure what the "#" represents. Thank you for your time.
This is purely a documentation thing: the # is generally used to signify an instance method and the . a class method (also called a static method).
For instance:
Schema#set: this means that instances of the class Schema will have a method called set(). Example:
var dogSchema = new Schema(...); // create an instance of `Schema`
dogSchema.set('strict'); // call the instance method `set()`
Notice that you don't actually use the # character here, it's still a . in real code.
Schema.indexTypes: this means that the class Schema itself has a method indexTypes(). Example:
var types = Schema.indexTypes(); // get the list of index types
More on instance and class/static methods in JavaScript can be found here.

OOP with MVC using Mongoose & Express.js

I'm creating an Express.js app in which I want to use the MVC pattern and Mongoose for the document mapping to a MongoDB database. I've created a folder for models and I want to derive everything from (Javascript's version of) abstract classes for better code organization.
I'm confused about what the best way is to organize the abstract classes and set default values that each instance of the models should be. For example, one way is to use Mongoose Schemas for abstract classes, and then use Mongoose models for the models themselves:
Feline.js:
var mongoose = require('mongoose');
var Feline = mongoose.Schema({
size: 'Number'
});
Feline.methods.getSize = function () {
return this.size;
}
module.exports = Feline;
HouseCat.js:
var mongoose = require('mongoose')
, FelineSchema = require('./Feline.js');
var HouseCatModel = mongoose.model('HouseCat', FelineSchema)
, HouseCat = new HouseCatModel({
size: 1 //Domesticated cats are small
});
module.exports = HouseCat;
There are a few problems with this design. For one, I would think there must be a better way to set specific properties for the each model without instantiating a new model object each time the client wants to create a new instance of a model type. For another, using this scheme, Mongoose has to be required in every model file, and the code is custom-tailored to use mongoose, which means it will be difficult to switch to another ODM if we want to do that in the future.
Is there any better way of coding this? And is there any design pattern which is easy enough to implement in Node that will allow for easy changing of the ODM?
As mongoose is specific to mongodb, this will be a hard task to abstract its behaviour.
The easiest way to do it is to set an interface for all ODMs and use an adapter pattern where mongoose is an "adaptee". Then, you can use a module providing some dependency injection to replace the used ODM.
As it is a really long task, I cannot give you some code. Moreover, it may be a pain to implement that kind of thing in javascript because it does not provide strong OOP natively. However, I can suggest you to take a look at some frameworks which can help you to do that like Danf for instance which provides a strong OOP paradigm with interfaces, classes, inheritance and a powerful dependency injection.

Is possible to add to already loaded schema some new static functions from some file?

Is possible to add to already loaded schema some new static functions from some file ?
I tried like to extends schema in mongoose
_ = require('lodash');
var schema = new mongoose.Schema(model.schema, model.options);
_.extend(schema, require('../extension/person_statics'));
but I get error
throw new MongooseError.OverwriteModelError(name);
^
OverwriteModelError: Cannot overwrite `Person` model once compiled.
Sorry, it is not possible to modify or extend a schema that was compiled.
The best practices to create a mongoose schema, is first of all initialize all your models with its specific schemas, and then compile all together.
This workflow may be difficult some times, I recommend you that use a framework for your models.
Check this framework for express and mongoose:
https://github.com/codexar/rode
The models are compiled on demand to prevent your problem.
I hope I have helped!

Mongoose: Using model or schema provided by a module from npm/node_modules

Say I have an application that defines a few models and creates the global Mongoose connection (mongoose.connect(...)). The app also relies on some models defined by a module in the node_modules directory. The problem that I'm running into is that the application and the separate module do not share the same global connection object.
Okay, fine. Rather than having the module export a model it can just export the schema and the main application can register it with the connection. In the app there would be something like:
var SomeSchema = require('somemodule').SomeSchema;
mongoose.model('SomeModel', SomeSchema);
Unfortunately this isn't working either. When the model is registered, Mongoose is checking whether the given schema is an instance of mongoose.Schema (here). When SomeSchema was defined (in the separate module) it creates the schema with new mongoose.Schema({ ... }) where mongoose is required from the module's local dependency tree. When the application registers the schema it uses the mongoose required from the application's dependencies. Since the two copies of mongoose are not the same object the given schema is not an instance of mongoose.Schema and an error is thrown.
Do you have any recommendations here? I was thinking one potential solution would be to have the module create a "plugin" function that accepts the schema and adds all the paths, methods, etc. The main app would create an empty schema and add the plugin. Something like:
var somePlugin = require('somemodule').somePlugin;
var SomeSchema = new mongoose.Schema();
SomeSchema.plugin(somePlugin);
mongoose.model('SomeModel', SomeSchema);
Are there any alternatives?
Thanks a lot.
I got around this problem by hacking the prototype of the schema to use the correct instance of mongoose.Schema so that it will pass the internal Mongoose instanceof check. So for your example, I would add a line like this:
var SomeSchema = require('somemodule').SomeSchema;
SomeSchema.__proto__ = mongoose.Schema.prototype;
mongoose.model('SomeModel', SomeSchema);
It's certainly not kosher but it works for me!

Resources