Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose behavior and schema

I am learning nodejs along with mongodb currently, and there are two things that confuse me abit.

(1), When a new Schema and model name are used (not in db), the name is changed into its plural form. Example:

mongoose.model('person', personSchema);

in the database, the table will be called "people" instead. Isn't this easy to confuse new developer, why has they implemented it this way?

(2), Second thing is that whenever I want to refer to an existing model in mongoDb (assume that in db, a table called people exists). Then in my nodejs code, I still have to define a Schema in order to create a model that refer to the table.

personSchema = new mongoose.Schema({});
mongoose.model('person',personSchema);

The unusual thing is, it does not seem to matter how I define the schema, it can just be empty like above, or fill with random attribute, yet the model will always get the right table and CRUD operations performs normally.

Then what is the usage of Schema other than defining table structure for creating new table?

Many thanks,

like image 414
MikeNQ Avatar asked Jul 10 '14 05:07

MikeNQ


People also ask

What does schema do in Mongoose?

In mongoose, a schema represents the structure of a particular document, either completely or just a portion of the document. It's a way to express expected properties and values as well as constraints and indexes. A model defines a programming interface for interacting with the database (read, insert, update, etc).

Does Mongoose need schema?

Everything in Mongoose starts with a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection.

What is Mongoose model and schema?

A Mongoose model is a wrapper on the Mongoose schema. A Mongoose schema defines the structure of the document, default values, validators, etc., whereas a Mongoose model provides an interface to the database for creating, querying, updating, deleting records, etc.

What is schema path in Mongoose?

You can think of a Mongoose schema as the configuration object for a Mongoose model. A SchemaType is then a configuration object for an individual property. A SchemaType says what type a given path should have, whether it has any getters/setters, and what values are valid for that path.


1 Answers

Actually two questions, you usually do better asking one, just for future reference.

1. Pluralization

Short form is that it is good practice. In more detail, this is generally logical as what you are referring to is a "collection" of items or objects rather. So the general inference in a "collection" is "many" and therefore a plural form of what the "object" itself is named.

So a "people" collection implies that it is in fact made up of many "person" objects, just as "dogs" to "dog" or "cats" to "cat". Not necessarily "bovines" to "cow", but generally speaking mongoose does not really deal with Polymorphic entities, so there would not be "bull" or "bison" objects in there unless just specified by some other property to "cow".

You can of course change this if you want in either of these forms and specify your own name:

var personSchema = new Schema({ ... },{ "collection": "person" });

mongoose.model( "Person", personSchema, "person" );

But a model is general a "singular" model name and the "collection" is the plural form of good practice when there are many. Besides, every SQL database ORM I can think of also does it this way. So really this is just following the practice that most people are already used to.

2. Why Schema?

MongoDB is actually "schemaless", so it does not have any internal concept of "schema", which is one big difference from SQL based relational databases which hold their own definition of "schema" in a "table" definition.

While this is often actually a "strength" of MongoDB in that data is not tied to a certain layout, some people actually like it that way, or generally want to otherwise encapsulate logic that governs how data is stored.

For these reasons, mongoose supports the concept of defining a "Schema". This allows you to say "which fields" are "allowed" in the collection (model) this is "tied" to, and which "type" of data may be contained.

You can of course have a "schemaless" approach, but the schema object you "tie" to your model still must be defined, just not "strictly":

var personSchema = new Schema({ },{ "strict": false });
mongoose.model( "Person", personSchema );

Then you can pretty much add whatever you want as data without any restriction.

The reverse case though is that people "usually" do want some type of rules enforced, such as which fields and what types. This means that only the "defined" things can happen:

var personSchema = new Schema({
    name: { type: String, required: true },
    age: Number,
    sex: { type: String, enum: ["M","F"] },
    children: [{ type: Schema.Types.ObjectId, ref: "Person" }],
    country: { type: String, default: "Australia" }
});

So the rules there break down to:

  1. "name" must have "String" data in it only. Bit of a JavaScript idiom here as everything in JavaScript will actually stringify. The other thing on here is "required", so that if this field is not present in the object sent to .save() it will throw a validation error.

  2. "age" must be numeric. If you try to .save() this object with data other than numeric supplied in this field then you will throw a validation error.

  3. "sex" must be a string again, but this time we are adding a "constraint" to say what the valid value are. In the same way this also can throw a validation error if you do not supply the correct data.

  4. "children" actually an Array of items, but these are just "reference" ObjectId values that point to different items in another model. Or in this case this one. So this will keep that ObjectId reference in there when you add to "children". Mongoose can actually .populate() these later with their actual "Person" objects when requested to do so. This emulates a form of "embedding" in MongoDB, but used when you actually want to store the object separately without "embedding" every time.

  5. "country" is again just a String and requires nothing special, but we give it a default value to fill in if no other is supplied explicitly.


There are many other things you can do, I would suggest really reading through the documentation. Everything is explained in a lot of detail there, and if you have specific questions then you can always ask, "here" (for example).

So MongoDB does things differently to how SQL databases work, and throws out some of the things that are generally held in "opinion" to be better implemented at the application business logic layer anyway.

Hence in Mongoose, it tries to "put back" some of the good things people like about working with traditional relational databases, and allow some rules and good practices to be easily encapsulated without writing other code.

There is also some logic there that helps in "emulating" ( cannot stress enough ) "joins", as there are methods that "help" you in being able to retrieve "related" data from other sources, by essentially providing definitions where which "model" that data resides in within the "Schema" definition.

Did I also not mention that "Schema" definitions are again just objects and re-usable? Well yes they are an can in fact be tied to "many" models, which may or may not reside on the same database.

Everything here has a lot more function and purpose than you are currently aware of, the good advice here it to head forth and "learn". That is the usual path to the realization ... "Oh, now I see, that's what they do it that way".

like image 61
Neil Lunn Avatar answered Nov 13 '22 00:11

Neil Lunn