takeaway

In order to understand some operations of Mongoose mentioned in the last article, I hereby share the introduction and operation of Mongoose, which basically covers most of the basic methods of use. For specific operations, you can move to watch the introduction of the official website, which is linked here. In fact, the purpose of writing these two articles is to help themselves better digest this part of the knowledge, with actual combat and article record way to strengthen memory and hand knocking ability, I hope partners can also act together, this part of the knowledge is not as difficult as we imagine, come on with 💪! If this article is of any help to you, please like it. If you have any shortcomings and mistakes ❌, please point them out in the comments.

Introduce a,

Mongoose is an object model tool for portable operation of mongodb in node.js asynchronous environment. Mongoose is the nodeJS driver and cannot be used as a driver for other languages.

Second, the characteristics of

  • Design non – relational database through relational database idea.
  • Based on themongodbDrive, simplify operation.
  • Used to operatemongodbDatabases are more flexible and secure.

Three, installation and use

1. Install

npm install mongoose -S

2. The introduction ofmongooseConnect to the database


const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true });

Copy the code

You can create a new library named test at the same time you connect to the database. You can customize it. The default is test.

{useNewUrlParser: true} Resolves warning messages

3. DefineSchema

Schema in a database is a collection of database objects. Schema is a kind of data Schema used in Mongoose. It can be understood as the definition of table structure. Each Schema maps to a collection in mongodb, which does not have the ability to manipulate databases.


const TestSchema = mongoose.Schema({
    username: String.password: String
});

Copy the code

4. Create the data model

With the Schema defined, the next step is to generate the Model. A Model is a Schema generated Model that can perform operations on a database.

Mongoose. Model can pass in two parameters, or three parameters.

Mongoose. Model (Parameter 1: model name (uppercase), parameter 2: Schema);

Mongoose. Model (Parameter 1: model name (uppercase), parameter 2: Schema, database set name);

If you pass in two arguments: the model will connect to a complex database with the same model name, such as creating the model as follows, the model will operate on the set of Users.

const User = mongoose.model(‘User’, UserSchema);

If three arguments are passed: the name of the collection defined by the third argument of the model default operation.

5. Data operation

<1> Find data

Parameter 1 is the lookup condition, and parameter 2 is the callback function


User.find({}, (err,docs) => {
    if(err) return;
    console.log(docs);
});

Copy the code
<2> Add data

const u = new User({ // Instantiate the model and pass in the added data
    username: 'hdove'.password: '123456'
});

u.save();// Perform a save operation, or pass in a callback function

Copy the code
<3> Modify data

User.updateOne({'_id': '1'}, {name: 'hdove1'}, (err, docs) => {
    if(err) return;
    console.log(docs);
});

// Change the name of the data whose id is 1 to hdove1. This id does not need to be converted through the ObjectID provided with mongodb.

Copy the code
<4> Delete data

User.deleteOne({'_id': '1'}, (err, docs) => {
    if(err) return;
    console.log(docs);
});

// Delete data whose id is 1

Copy the code

Default parameters

Mongoose Default parameter. When adding data, if no data is passed in, the default parameter is used.


const TestSchema = mongoose.Schema({
    username: String.password: String.status: {
        type: Number.default: 1 // Set the default parameters}});Copy the code

Five, modular

Modularity is actually used to simplify some of our operations, reduce the code logic, more hierarchical, easier to operate, especially under the condition of too much code. Here is a simple modularization step to explain what it does.

1. File directory

+– model

| + — db. Js / / database connections

| + — user. Js / / user model

+– app.js

2. db.js


const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/user', { useNewUrlParser: true }, (err) => {
    if(err) {
        console.log(err);
        return;
    }
    console.log('Database connection successful');
});

module.export mongoose;

Copy the code

3. user.js


const { Schema, model } = require('./db.js');

const UserSchema = new Schema({
    name: String.age: Number.status: {
        type: Number.default: 1}});module.export = model('User', UserSchema, 'user');

Copy the code

4. app.js


const UserModel = require('./model/user');

User.find({}, (err, docs) => {
    if(err) return;
    console.log(docs);
});

Copy the code

Six, performance problems

With that in mind, let’s look at a piece of code


console.time('user');
const UserModel = require('./model/user');
console.timeEnd('user');

console.time('test');
const TestModel = require('./model/test');
console.timeEnd('test');

Copy the code

We first guess the printing time is about the same or a lot less?

The answer is by a lot.

The result is something like:


user: 1154ms

test: 2ms

Copy the code

Why is that?

In fact, Mongoose uses a singleton mode, just as we simply encapsulated in the last article. After the connection is successful, the link object is directly returned for the second time without reconnection. Speed up, so you don’t have to worry too much about performance, and Mongoose has done most of the optimization.

Predefined and custom operators

1. Predefined operators

Lowercase, uppercase, trim

Mongoose provides predefined schema operators to do some formatting on our added data.


const UserSchema = new Schema({
    name: {
        type: String.trim: true // delete the space left and right}});Copy the code

2. Customize modifiers

In addition to mongoose’s built-in modifiers, you can format data when adding data using the set(recommended) modifier, and format data when retrieving data from an instance using GET (not recommended).

(1)set

To implement a simple operation, we store https://www.baidu.com in the database when the user enters something like www.baidu.com


const UserSchema = new Schema({
    name: {
        type: String.trim: true // delete the space left and right
    },
    website: {
        type: String,
        set(params){ // This field is processed when adding data
            // Params can retrieve the value of website and return the actual value saved in the database
            if(! params)return ' ';
            
            if( params.indexOf('http://')! = =0 && params.indexOf('https://')! = =0) {return 'https://' + params;
            }
            returnparams; }}});Copy the code
(2)get

When we get data from the database, we actually get the actual data stored in the database. Get is only used when we create new data, we can see the modified content. However, the data stored in the database is still the input data, so it has no impact, so it is not too useful and is not recommended.


const UserSchema = new Schema({
    name: {
        type: String.trim: true // delete the space left and right
    },
    website: {
        type: String,
        get(params) {
            if(! params)return ' ';
            
            if( params.indexOf('http://')! = =0 && params.indexOf('https://')! = =0) {return 'https://' + params;
            }
            returnparams; }}});const UserModel = model('User', UserSchema);

const User = new UserModel({
    website: 'www.baidu.com'
});

console.log(User.website); // https://www.baidu.com

User.save(); // { website: 'www.baidu.com' }

Copy the code

Mongoose index, CURD, static method of extending Model and instance method

1. The mongoose index

Indexes can greatly improve query efficiency. If there is no index, MongoDB must scan every file in the collection and select the records that meet the query conditions when reading data.

The query efficiency of scanning the whole collection is very low, especially when dealing with a large amount of data, the query can take tens of seconds or even a few minutes, which is very fatal to the performance of the website.

An index is a special data structure that is stored in a collection of data that is easy to traverse and read. An index is a structure that sorts the values of one or more columns in a database table


const UserSchema = new Schema({
    sn: {
        type: String.index: true // Set the normal index
    },
    name: {
        type: String.unique: true // Unique index}});Copy the code

2. CURD(add, delete, modify and check operation)

Some curds are built into Mongoose, see the documentation for details

  • Model.deleteMany()
  • Model.deleteOne()
  • Model.find()
  • Model.findById()
  • Model.findByIdAndDelete()
  • Model.findByIdAndRemove()
  • Model.findByIdAndUpdate()
  • Model.findOne()
  • Model.findOneAndDelete()
  • Model.findOneAndRemove()
  • Model.findOneAndReplace()
  • Model.findOneAndUpdate()
  • Model.replaceOne()
  • Model.updateMany()
  • Model.updateOne()

3. Static methods for Model and instance methods

Use the custom CURD method.


const UserSchema = new Schema({
    name: {
        type: String
    },
    age: Number
});

// Static method
UserSchema.statics.findByName = function(name, cb) {
    // Use find to get the name data, this keyword to get the current model
    this.find({'name': name}, function(err, docs) = >{
        cb(err, docs); 
    });
}

// Instance methods (rarely used)
UserSchema.mothods.print = function(name, cb) {
    console.log('I'm an instance method');
    console.log(this.name);
}

const UserModel = model('User', UserSchema);

const user = new UserModel({
    name: 'hdove'
});

user.print(); // I am an instance method hdove

Copy the code

Ix. Data verification

1. Built-in data verification method

  • requiredIndicates that this data must be passed in
  • maxFor data of type Number, maximum value
  • minFor data of type Number, minimum value
  • enumEnumeration type that requires data to satisfy an enumeration value
  • matchThe added data must comply with the match(re) rule
  • maxlengthThe maximum length
  • minlengthMinimum length

2. Customize the verification method

Similar to set above


const UserSchema = new Schema({
    name: {
        type: String.validate: name= > { // The length of name is greater than 10
            return name.length > 10}}});Copy the code

X. Use aggregate polymerization pipeline

Aggregation pipes allow you to transform and combine documents in a collection.

Actual use: table associated query, data statistics.

Db.collection_name. Aggregate ([{},… ) method to build and is to use aggregation pipes.

1. Common pipe operators

  • $projectAdd, delete, and rename fields
  • $matchCondition match. Only documents that meet the criteria can proceed to the next stage
  • $limitLimit the number of results
  • $skipSkip the number of documents
  • $sortsort
  • $groupCondition combination result statistics
  • $lookupData used to introduce other collections

2. Common pipe expressions

The pipe operator is “key” and the pipe expression is “value”.

  • $addToSetDeduplicates the value of a specified field in the document
  • $maxThe document specifies the maximum value for a field
  • $minThe document specifies the maximum value for a field
  • $sumThe document specifies field summation
  • $avgAverage the fields specified by the document
  • $gtGreater than a given value
  • $ltLess than a given value
  • $eqEqual to a given value

3.$project

Modify the structure of a document, which can be used to rename, add, or delete fields in the document


// Only a and B fields are returned
Model.aggregate([
    {
        $project: { a: 1.b: 1}}]);Copy the code

4.$match

Used to filter documents, similar to the arguments in the find() method


// Return data that matches price greater than or equal to 100
Model.aggregate([
    {
        $match: { 'price': { $gte: 100}}}]);Copy the code

4.$limit


// Only one data is returned
Model.aggregate([
    {
        $limit: 1}]);Copy the code

5.$skip


// Skip the first one and return the following data
Model.aggregate([
    {
        $skip: 1}]);Copy the code

6.$sort

Sort the documents in the collection.


// In reverse order of price
Model.aggregate([
    {
        $sort: { 'price': - 1}}]);Copy the code

7.$group

Group documents in a collection that can be used for statistical results.


// Group by order_id and count the number of groups
Model.aggregate([
    {
        $group: {_id: "$order_id".total: {$sum: "$num"}}}]);Copy the code

8.$lookup


Model.aggregate([
    {
        $lookup: {
            from: 'student'.// associate the student table
            localField: 'class_id'.// This table field is named class_id
            foreignField: 'class_id'.// The field in the associated table is class_id
            as: 'students' // Use the STUDENTS field to receive content that meets the requirements}},]);Copy the code

9. Simple application (associate a table)

First, let’s create two new collections.

Teacher’s table

Students table

Implement table associative query, here will not create the following two models, I believe you can complete their own, save time, we continue.

To get an ObjectID from Mongoose, use Mongoose.Types. ObjectID


// Query the student table information and the corresponding teacher information by class_id

const StudentModel = require('./Student');
const ClassModel = require('./Class');

StudentModel.aggregate([
    {
        $lookup: {
            from: 'class'.localField: 'class_id'.foreignField: 'class_id'.as: 'teachers'
        }
    }
], (err, docs) => {
    if(err) return;
    
    console.log(docs); }); Return data: [{...other,teachers: [{
        teacher: 'lisi1'. other }] }, ... other ]// query teacher 1's student

ClassModel.aggregate([
    {
        $lookup: {
            from: 'student'.localField: 'class_id'.foreignField: 'class_id'.as: 'students'}}, {$match: { class_id: 1 }
    }
], (err, docs) => {
    if(err) return;
    
    console.log(docs);
});

Copy the code

3. Complex applications (associating multiple tables)

Despite the name complex application, but it is very simple to use, as long as we master the simple application method is ok, the method is to overlay operation.


const StudentModel = require('./Student');
const ClassModel = require('./Class');

StudentModel.aggregate([
    {
        $lookup: {
            from: 'class'.localField: 'class_id'.foreignField: 'class_id'.as: 'teachers'}}, {$lookup: {... Associated arbitrary table}}], (err, docs) => {if(err) return;
    
    console.log(docs);
});

Copy the code

11. Data export and restoration

1. Export

Mongodump -h 127.0.0.1 -d koa -o Export directory

2. The reduction

Mongorestore -h 127.0.0.1 -d Specifies the name of the imported database library

Xii. Recommendation

  • Koa2 + JWT + mongodb
  • Redux and Redux-Saga
  • React component communication, you need to know this at least, right?