It’s not JavaScript, it’s TypeScript. VSCode’s JS tooling is also TypeScript tooling, the two are the same. This doesn’t mean you’re writing TypeScript, it just means that you can see the TypeScript definitions if they’re available, they are there to help you.
This is a function called model that returns a type called Model.
It has a name parameter that is mandatory…
…and the parameters schema, collection and skipInit which are optional (the ? after them denotes this)
Schema is a specific, defined type (that is why it’s capitalised). You should be able to right-click on the argument and select “go to definition” to show the code where it is defined, or “go to type definition” to view the type. In this case, Schema is a class
string and boolean are built in types, they are what they say on the tin.
The benefit of this is that if you typed const Test = mongoose.model(1) it would show an error (red squiggly line under the 1) straightaway: the first parameter of the model function has to be a string. If you were using TypeScript rather than JavaScript, this would also cause the compilation from TS → JS to fail with an error stating you were trying to pass a number instead of a string to the function.
The angle brackets denote that this is what’s called a generic. It means that it can work over a number of different underlying types. In this case, a model creates a Document type which may include the Schema. The Schema may be one of a variety of different types, so the second parameter in those angle brackets is saying it’s going to work on an object.
I need to emphasise that you don’t need to know all this, the hints here are there to describe the shape of the API you’re working with (Mongoose), and are included from the Mongoose code, but you can just ignore them if you want.
Thank you very much for your detailed and systematic explanation. Much appreciated. It gives me the much needed guidance to further my studies.
You mentioned the model function returned an instance of the Model class. However, when I did a typeof on the variable assigned with the returned value of the model function, it states that a function is returned instead of object. (#1)
Referring to the code snippet below taken from the models doc at mongoosejs website, am I right to say that create() and insertMany() are properties of the constructor function that was returned by mongoose.model() and assigned to Tank?
Thanks.
var Tank = mongoose.model('Tank', yourSchema);
Tank.create({ size: 'small' }, function (err, small) {
if (err) return handleError(err);
// saved!
});
Tank.insertMany([{ size: 'small' }], function(err) {
});
No, the function doesn’t have properties. A constructor creates an object with those functions attached to it.
The point of the model function (the class constructor) is that it builds an object populated with data you pass it relating to the DB Schema, and it attaches some predefined functions to it that now operate on that specific data.
This is what that confused me. There is no code (like new Tank()) that instantiate the object before calling the create/insertMany method using the dot notation.
Since Tank is a constructor function, Tank.create() seems to have the syntax of a constructor function calling the create method. That’s why I thought create() could be a property of the constructor function.
Tank.create()
<constructor function>.<method> // ??
vs
(new Tank()).create()
<object>.<method> // the usual way of calling a method?
Thank you for your patience on this topic! Much appreciated!
It will work like this. Note I’m on phone and I don’t want to spelunk through the Mongoose codebase to show exactly how they’ve set it up, it will be doing a helluva lot more stuff, this is drastically simplified and doesn’t actually do anything:
class Model {
constructor (name, schema) {
this.name = name;
this.schema = schema;
}
static create(name, schema) {
return new Model(name, schema);
}
}
Now this allows you to either do
new Model("MyName", mySchema)
Or
Model.create("MyName", mySchema)
They both do the same thing
Without class syntax:
function Model (name, schema) {
this.name = name;
this.schema = schema;
}
Model.create = function(name, schema) {
return new Model(name, schema);
}
Is there a way to know from the API doc what is the exact return type of a given method?
Eg.
Model.find()
Parameters
filter «Object|ObjectId»
[projection] «Object|String» optional fields to return, see Query.prototype.select()
[options] «Object» optional see Query.prototype.setOptions()
[callback] «Function»
Returns:
«Query»
The doc indicates returning a Query object but it does not indicate that it is actually an Array of Documents. I used console.log(myModel.find()) to know that. Likewise for other methods, I have to console.log for the actual returns. Is there a better way to know?