nodejs-mongoose

Learn about databases

  1. Relational database is a database based on the relational model.
    • Data is stored in the form of table, each row in the table is a record, each column is a field, and each field has a data type. Relational databases use Structured Query Language (SQL) to query and manage data.
    • Advantages: data clear structure, data clear relationship, good data consistency.
    • Disadvantages: limited scalability. Not suitable for processing massive data and unstructured data.
  2. == Non-relational database (NoSQL) == is an unstructured database.
    • Data is stored in the form of key-value pairs, documents, graphics, etc. Non-relational database does not require a predefined schema, and new fields and data types can be added at any time. Non-relational databases typically use unstructured query languages to query and manage data.
    • Advantages: High scalability, suitable for processing unstructured data and massive data, and support for distributed deployment.
    • Disadvantages: The data structure is not clear enough, the data relationship is not clear enough, and the data consistency is slightly poor.

In general, relational databases are suitable for processing structured data, such as orders, accounts, etc.; non-relational databases are suitable for processing big data, unstructured data and real-time data, such as user logs, social media data, etc. Beginners can choose the appropriate database according to their needs.

Use of mongoose

Introduce mongoose and connect mongodb

const mongoose = require('mongoose');
// Connect to the specified database (if it does not exist, you need to create the database first)
mongoose
  .connect('mongodb://localhost:27017/ami')
  .then(() => console.log('connected!'));

Preset table rules and create corresponding tables

// Obtain the operation object of setting table rules => schema outline, outline
const {<!-- --> Schema } = mongoose;
// default table rules
const userSchema = new Schema(
  {<!-- -->
    name: {<!-- -->
      type: String,
      /* limit the length of the string */
      maxLength: 10,
      minLength: 1,
  },
    age: {<!-- -->
      type: Number,
      required: true, //required
      /* Verify the size of the number */
min: 0,
/* You want to give the user a hint */
max: [150, 'The age cannot exceed 150, don't be too ridiculous!'],
    },
    sex: {<!-- -->
type: String,
/* Enumeration: preset field value content */
enum: ['male', 'female'],
},
    tag: {<!-- -->
      type: Array,
      validate: {<!-- -->
        /* Check logic */
        validator(value) {<!-- -->
          /* value => tag field value */
          /*
             Perform a series of verification judgments on the value
           */
          /* return true or false */
        },
        message: 'error message in the tag field',
      },
    },
    hobbies: String,
  },
  {<!-- -->
    versionKey: false, //Remove the version number
  }
);
// create a table (get the operation object of the table)
const userInfoTable = mongoose.model('userInfoTable', userSchema);

Add data

//Add data ==> batch add
userInfoTable
  .create(
    {<!-- -->
      // _id: new mongoose.Types.ObjectId(), //mongodb will automatically create the id domain name for you, no need to write it yourself
      name: 'Coke',
      age: 17,
      sex: 'Male',
      tags: 'handsome, smart'.split(','),
      hobbies: 'playing basketball',
    },
    {<!-- -->
      // _id: new mongoose.Types.ObjectId(), //mongodb will automatically create the id domain name for you, no need to write it yourself
      name: 'ami',
      age: 161,
      sex: 'Male',
      tags: 'handsome, smart'.split(','),
    },
    ...
  )
  .then(() => {<!-- -->
    console.log('success!');
  })
  .catch(() => {<!-- -->
    console.log('failure');
  });

Find data

findOne(), findById(), find()

userInfoTable
  .findOne({<!-- -->
    age: 161,
  })
  .then((value) => console.log(value));
 
userInfoTable
  .findById({<!-- -->
    _id: '6453aed985f7f27723c1999e',
  })
  .then((value) => console.log(value));

// Return the result array, if no result is found, return an empty array
userInfoTable.find({<!-- --> age: 161 }).then((value) => console.log(value));

Fuzzy query of find()

/*
  Fuzzy query:
    => is achieved through the conditional operator

    Comparison query operators (for numbers):
      $gt | $lt | $gte | $lte | $eq | $ne | => greater than | less than | greater than or equal to | less than or equal to | equal to | not equal to
    Logical query operator (judgment):
      $or | $and |$nor => or | and | not
    Existence judgment (applicable to arrays):
      $exists:true | false; ==> Determine whether a field name exists
      $in | $nin | $size ==> determine the length of the array | $all
    
    $where traverses the database, and the returned boolean value determines whether the data should be left or not
    Regular expression: ===> eg. find({name:/a/,})
*/

Use of comparison query operators

userInfoTable
  .find({<!-- -->
    // When the value is no longer a specific value, it is expressed in the form of an object
    age: {<!-- -->
      // $lt: 18, //less than 18
      // $lte: 18, // less than or equal to 18
      // $gt: 18, //less than 18
      // $gte: 18, // greater than or equal to 18
      // $eq: 16 // equal to 16
      $ne: 16, // not equal to 16
    },
  })
  .then((userArr) => console.log(userArr));
Use of logical query operators
userInfoTable
  .find({<!-- -->
    // Among the multiple conditions, the data that can satisfy any one of the conditions is in line with
    $or: [
      {<!-- -->
        age: {<!-- -->
          $gt: 16,
        },
      },
      {<!-- -->
        sex: 'female',
      },
    ],
// Multiple conditions must be met
// and is used less, because the find parameter conforms to and
$and: [
{<!-- -->
age: {<!-- -->
$gt: 16,
},
},
{<!-- -->
sex: 'female',
},
],
// when multiple conditions are not met
$nor: [
{<!-- -->
age: {<!-- -->
$gt: 16,
},
},
{<!-- -->
sex: 'female',
},
],
  })
  .then((userArr) => console.log(userArr));
Existence judgment (applicable to arrays) and the use of $where
userInfoTable
  .find({<!-- -->
    tags: {<!-- -->
      // Does the value exist in the current field value (array)
      // $in: 'handsome',
      // Data with any value in the current field value is eligible! ! ! ! ! ! ! ! ! ! ! !
      // $in: ['smart', 'handsome'],
      // does not exist
      // $nin: 'handsome',
      // $nin: ['smart', 'handsome'],
    },
    hobbies: {<!-- -->
      // Does this field exist
      $exists: true,
    },
    tags: {<!-- -->
      // $size: 3, //The length of the array is 3
      $all: ['handsome', 'smart'], // only when there are all conditional values in the array value
    },
    // $where traverses the database, and the returned boolean value determines whether the data should be left or not
    $where: function () {<!-- -->
      // return true means to keep the data ==> similar to filtering
      return this. age > 16;
    },
    name: /a/,
  })
  .then((userArr) => console.log(userArr));

The use of parameters projection and options in find()

/*Filter fields: use the second parameter projection of the find() function*/
/*Process the query data: use the third parameter options of the find() function*/
userInfoTable
  .find(
    {<!-- -->
      $where: function () {<!-- -->
        return this.tags.length > 1;
      },
    },
    /* filter field name */
    {<!-- -->
      name: true, //Only take the name field, filter out the area field name
      tags: true,
      _id: false, //filter out the field name,
    },
    /* Process the queried data */
    {<!-- -->
      // Sort: descending, ascending
      sort: {<!-- -->
        // age: 1, // ascending order
        age: -1, // descending order
      },
      /* Skip the first n results */
      skip: 6,
      /* Remove n pieces of data */
      limit: 3,
      /*
        Implement pagination:
          12 pieces of data, 4 pieces of data are 1 page

          Use skip and limit together
      */
    }
  )
  .then((userArr) => console.log(userArr));

Delete data deleteMany, deleteOne

Notice:

  1. Best to delete based on unique values
  2. Assignment of database permissions (generally it is not possible for you to have permission to delete important data ==> the work of a database engineer),
userInfoTable
  .deleteMany({<!-- -->
    age: 156,
  })
  .then((data) => {<!-- -->
    /*
      Printed data: { acknowledged: true, deletedCount: 0 }
      acknowledged: success status is true
      deletedCount: How many items have been successfully deleted
    */
    console. log(data);
  });

Update (modify) data updateOne, updateMany, findByIdAndUpdate

  1. updateOne to modify the first piece of data queried
  2. updateMany modify all queried data
userInfoTable
  .updateOne(
    // Query conditions
    {<!-- -->
      name: 'Coke',
    },
    /* What to change to */
    {<!-- -->
      /* modify the value of multiple fields at the same time */
      $set: {<!-- -->
        name: 'Coke' + 1,
        age: 20,
      },
    }
  )
  .then((data) => {<!-- -->
    /*
      {
        acknowledged: true,
        modifiedCount: 1,
        upsertedId: null,
        upsertedCount: 0,
        matchedCount: 1
      }
    */
    console.log('updated successfully', data);
  });

Update data to update the array

userInfoTable
  .updateMany(
    // Query conditions
    {<!-- -->
      name: 'Sauron 1',
      tags: {<!-- -->
        // element matches
        $elemMatch: {<!-- -->
          /* When it exists, the subscript of the member will be returned */
          $in: 'May Day Overtime',
        },
      },
    },
    /* What to change to */
    {<!-- -->
      /* modify the value of multiple fields at the same time */
      $set: {<!-- -->
        name: 'Sauron' + 1,
        age: 20,
      },
      /* Modify the value of the array */
      /*
      $set: {
        // direct override ===> low performance
        tags: ['Three Swords', 'One-eyed'],
      },
      */
      /* Append only for arrays (repeat values are allowed) */
      $push: {<!-- -->
        /* tags: {
          // Add item by item
          $each: ['smart', 'handsome'],
        }, */
        /* add array directly */
        tags: ['smart', 'handsome'],
      },
      /* deduplicated array append */
      $addToSet: {<!-- -->
        tags: {<!-- -->
          $each: ['smart', 'handsome'],
        },
      },
      /* Modify the value of the specified subscript in the array */
      $set: {<!-- -->
        'tags.2': 'May Day overtime',
      },
      /* remove the member from the array */
      $pop: {<!-- -->
        /* Delete one from the front */
        // tags: -1
        /* Delete one from the back to the front */
        tags: 1,
      },
      /* Based on the value, delete the specified member in the array */
      $pull: {<!-- -->
        tags: 'No overtime on May Day',
      },
      /* Delete multiple member values at once */
      $pull: {<!-- -->
        tags: {<!-- -->
          $in: ['smart', 'handsome'],
        },
      },
      /* Delete field (basically not used) */
      $unset: {<!-- -->
        sex: true,
      },
    }

    /* Get the subscript of the matching array element in the array that meets the criteria */
    // {<!-- -->
    // /* After element matching, if there is a member of "May Day Overtime", the subscript of the member will be returned and stored in $ */
    // $set: {<!-- -->
    // 'tags.$': 'No overtime on May Day',
    // },
    // }
  )
  .then((data) => {<!-- -->
    /*
      data: {
        acknowledged: true,
        modifiedCount: 1,
        upsertedId: null,
        upsertedCount: 0,
        matchedCount: 1
      }
    */
    console.log('updated successfully', data);
  });

Table Association

Generally, when the field value in a certain table needs to be an object, a new table will be created for association

let scoreSchema = new Schema({<!-- -->
  name: String,
  subject: {<!-- -->
    type: String,
  },
  result: Number,
  /* Define associated fields */
  refStudent: {<!-- -->
    /* To associate with a unique ID */
    type: mongoose.Types.ObjectId,
    // ref associated target table
    ref: 'student', //actual table name
  },
});

let studentInfoTable = mongoose. model('student', studentSchema);
let scoreInfoTable = mongoose. model('score', scoreSchema);

joint table query

scoreInfoTable
  .find({<!-- -->
    name: 'Li Hua',
  })
  .populate({<!-- -->
    /* Associated fields of the current table */
    path: 'refStudent',
    /* Association Table */
    model: studentInfoTable,
  })
  .then((res) => {<!-- -->
    console. log(res);
  });