zoukankan      html  css  js  c++  java
  • Mongoose

    1. 什么是Mongoose?

    mongoose是MongoDB的数据库的对象模型工具。可以通过操作在nodeJS中对mongoose的操作实现对数据库的操作。

    背景知识:

    ORM:Object Relational Mapping对象关系映射。

    是将对数据库的操作映射成对象的操作。(mongoose是一种ORM)

    ORM优点

    1. 屏蔽数据库操作的细节

    2.跨数据库平台

    2. 如何实现Mongoose?

    1. 创建映射对象

    const mongoose = require('mongoose');
    const conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    // 错误监听
    conn.on('error', function(err) {
        console.error(err);
    });
    // 连接监听
    conn.on('open', function() {
        console.log('连接成功');
    })

    2. 定义Schema类

    Schema类定义了字段的名称、类型、默认值

    const UserSchema = new mongoose.Schema({
      username: String,
      password: String,
    }, {collection: 'user'});// 第二个参数定义集合的名称

    其中Schema的完整类型示例如下:

      const personSchema = new mongoose.Schema({
        name: {type: String, required: true}, // 字符串
        binary: Buffer, // 二进制
        living: Boolean, // 布尔值
        birthday: {type: Date, default: Date.now}, // 日期类型
        age: Number, //Number类型
        // ObjectId类型
        _id: Schema.Types.ObjectId, // 主键
        _fk: Schema.Types.ObjectId, // 外键;其他集合的主键
        //数组类型
        array: [], 
        arrOfString: [String], //字符串数组
        arrOfNumber: [Number], //数字数组
        arrOfDate: [Date], //日期数组
        arrOfBuffer: [Buffer], //Buffer数组
        arrOfBoolean: [Boolean], //布尔数组
        arrOfObjectId:[Schema.Types.ObjectId] // ObjectId数组
        // 内嵌文档
        nested: {
          name: String
        }
      })

    3. 创建对象模型

    const User = conn.model('User', UserSchema);

    4. 创建实体对象

    const zhangsan = new User({username: 'zhangsan', password: 1});
    // 可以改成async函数
    zhangsan.save(function(err, result) {
      if (!err) {
        console.log(result)
      }
    })

    5. 常见操作方法

    let mongoose = require('mongoose');
    let conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
      useNewUrlParser: true,
      useUnifiedTopology: true
    }); 
    const UserSchema = new mongoose.Schema({
      username: {type: String, required: true},
      age: Number,
      password: String,
      createAt: {type: Date, default: Date.now}
    });
    const User = conn.model('User', UserSchema);
    
    (async function() {
      try{  
        // 插入文档
        let user1 = await User.create({username: "lyra", age: 18});
        let user2 = await User.create({username: "lee", age: 10});
        // 更新文档
        let updatedUser1 = await User.updateOne({username: 'lyra'}, {username: 'lyraLee'});
        let updatedUser2 = await User.updateMany({}, {password: '123456'});
        // 查询文档
        let findUser1 = await User.find({age: {$gte: 10, $lt: 12}});
        console.log(findUser1); // 返回一个数组
        let findUser2 = await User.findOne({});
        console.log(findUser2); // 返回一个对象
        let findUser3 = await User.findById({_id: '5e4d62bab945ba909211d280'});
        console.log(findUser3); // 返回一个对象
      } catch(err) {
        console.log(err);
      }
    })();

    6. 高级查询方法

    1. 带外键查询

    let mongoose = require('mongoose');
    let ObjectId = mongoose.Schema.Types.ObjectId;
    let conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
      useNewUrlParser: true,
      useUnifiedTopology: true
    }); 
    
    const UserSchema = new mongoose.Schema({
      username: {type: String, required: true},
      age: Number,
      password: String,
      createAt: {type: Date, default: Date.now}
    }, {collection: 'user'}); //指定集合名称为user;否则默认users
    const ArticleSchema = new mongoose.Schema({
      title: String,
      content: String,
      author: {type: ObjectId, ref: 'User'} //ref表明该字段为外键;对应模型名称
    });
    
    const User = conn.model('User', UserSchema);
    const Article = conn.model('Article', ArticleSchema);
    
    // 带外键查询
    (async function() {
      const user = await User.create({username: 'lyra', age: 10, password: 1});
      await Article.create({title: '标题', content: '内容', author: user._id})
      // 查看文章的信息-包含作者的具体信息-populate的参数是外键对应的字段名称
      const article = await Article.findById('5e4d6c2eb8ba3590edada416').populate('author'); 
      console.log(article)
    })()

    2. 分页查询

    // 分页查询
    const pageSize = 3;
    const pageNum = 2;
    const users = [];
    for(let i=0; i< 10; i++) {
      users.push({username: 'lyra'+i, password: i, age: 18+i})
    }
    (async function() {
      await User.create(users);
      User.find().sort({age: 1}).skip((pageNum-1)*pageSize).limit(pageSize).exec(function(err, result) {
        if(!err) {
          console.log(result);
        }
      })
    })();

    3. Mongoose模型扩展

    1. 静态方法和实体方法

    当某些逻辑存在重复使用的情况时,可以将其进行封装。

    优点:

    1. 当代码的逻辑修改时,不需要大面积修改原有代码。

    2. 方法的使用者不用关心内部的实现逻辑。

    扩展静态方法依据: 针对的整个集合(如:求年龄最大者);

    const mongoose = require('mongoose');
    const conn = mongoose.createConnection('mongodb://localhost:27017/school', {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    
    const { Schema } = mongoose;
    const UserSchema = new Schema({
      username: String,
      password: String,
      createAt: {type: Date, default: Date.now}
    })
    // 扩展Schema类静态方法;要位于model创建之前
    UserSchema.statics.login = function(username, password) {
      return this.findOne({username, password});
    }
    
    const User = conn.model('User', UserSchema);
    (async function() {
      await User.create({username: '1', password: '1'})
    })();
    
    // 静态方法校验
    (async function(username, password) {
      const result = await User.login(username, password);
      console.log(result);
    })('1', '1');

    扩展实体方法依据: 针对的是个体(如:用户是否已经成年);

    const mongoose = require('mongoose');
    const conn = mongoose.createConnection('mongodb://localhost:27017/school', {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    
    const { Schema } = mongoose;
    const UserSchema = new Schema({
      username: String,
      password: String,
      createAt: {type: Date, default: Date.now}
    })
    
    // 扩展实体方法;要位于model创建之前
    UserSchema.methods.login = function() {
      // 从实体获取模型的方法this.model('User')
      return this.model('User').findOne({username: this.username, password: this.password})
    }
    
    const User = conn.model('User', UserSchema);
    (async function() {
      await User.create({username: '1', password: '1'})
    })();
    
    // 实体方法校验
    (async function() {
      const user = new User({username: '1', password: '1'});
      const result = await user.login();
      console.log(result);
    })()

    2. 钩子-hook

    在具体的操作实现前后添加一些操作的逻辑。

    /**
     * 例如: 在注册的用户信息保存save()之前,需要将密码通过加盐算法进行加密
     */
    const mongoose = require('mongoose');
    const crypto = require('crypto');
    const conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    
    const { Schema } = mongoose;
    const UserSchema = new Schema({
      username: String,
      password: String,
      createAt: {type: Date, default: Date.now}
    }, {collection: 'user'});
    // save()前添加钩子
    UserSchema.pre('save', function(next) {
      this.password = crypto.createHmac('sha256', 'lyra').update(this.password).digest('base64');
      next();
    });
    const User = conn.model('User', UserSchema);
    
    (async function register(username, password) {
      const user = new User({username, password});
      user.save();
    })('a', '1');

    3. 虚拟属性-virtual

    4. 插件-plugin

    针对非自己创建的Schema,或者给定的Schema不允许直接操作时。

    插件代码:

    // schema是原始Schema; options是参数
    module.exports = function(schema, options) {
      // 添加字段
      schema.add({lastModified: Date});
      // 钩子;每次更新前添加变更时间
      schema.pre('save', function(next) {
        this.lastModified = new Date();
        next();
      })
    }

    逻辑代码:

    const mongoose = require('mongoose');
    const conn = mongoose.createConnection('mongodb://localhost:27017/mydb', {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    const UserSchema = new mongoose.Schema({
      username: String,
      password: String,
    }, {collection: 'user'});
    
    // 插件用于在保持原有Schema不变的基础上;修改Schema
    let plugin = require('./plugin');
    UserSchema.plugin(plugin, {index: true});
    const User = conn.model('User', UserSchema);
    User.create({username: 'lyra'});
  • 相关阅读:
    Logstash中如何处理到ElasticSearch的数据映射
    Filebeat+Logstash+ElasticSearch+Kibana搭建Apache访问日志解析平台
    Log stash学习笔记(一)
    Plupload设置自定义参数
    优先队列的基本算法(使用二叉堆构建优先队列)
    用OC基于数组实现循环队列
    循环队列的基本算法
    用OC基于链表实现链队列
    链队列的基本算法
    用OC实现一个栈:结合单链表创建动态栈
  • 原文地址:https://www.cnblogs.com/lyraLee/p/12353389.html
Copyright © 2011-2022 走看看