58 Node.js中操作mongoDB數(shù)據(jù)庫

技術(shù)交流 QQ 群:1027579432,歡迎你的加入!

歡迎關(guān)注我的微信公眾號:CurryCoder的程序人生

1.數(shù)據(jù)庫概述及環(huán)境搭建

1.1 為什么要使用數(shù)據(jù)庫
  • 動態(tài)網(wǎng)站中的數(shù)據(jù)都是存儲在數(shù)據(jù)庫中。
  • 數(shù)據(jù)庫可以用來持久存儲客戶端通過表單收集的用戶信息。
  • 數(shù)據(jù)庫軟件本身可以對數(shù)據(jù)進行更高效的管理。
1.2 什么是數(shù)據(jù)庫
  • 數(shù)據(jù)庫即存儲數(shù)據(jù)的倉庫,可以將數(shù)據(jù)進行有序的分門別類的存儲。它是獨立于語言之外的軟件,可以通過 API 去操作它。


    Node.js與數(shù)據(jù)庫交互.png
  • 常見的數(shù)據(jù)庫軟件有:mysql、mongoDB、oracle、redis 等
1.3 mondoDB 數(shù)據(jù)庫下載安裝
1.4 數(shù)據(jù)庫相關(guān)概念
  • 在一個數(shù)據(jù)庫軟件中可以包含多個數(shù)據(jù)倉庫,在每個數(shù)據(jù)倉庫中可以包含多個數(shù)據(jù)集合,每個數(shù)據(jù)集合中可以包含多條文檔(具體的數(shù)據(jù))。


    數(shù)據(jù)庫相關(guān)概念.png
1.5 Mongoose 第三方包
  • 使用 Node.js 操作 mongoDB 數(shù)據(jù)庫需要依賴 Node.js 第三方包 mongoose。
  • 使用 npm install mongoose 命令下載安裝
1.6 啟動 mongoDB
  • 在 cmd 中運行net start mongoDB即可啟動 mongoDB,否則 mongoDB 將無法連接。在 cmd 中運行net stop mongoDB即可關(guān)閉 mongoDB。
1.7 數(shù)據(jù)庫連接
  • 使用 mongoose 提供的 connect 方法即可連接數(shù)據(jù)庫。

    const mongoose = require("mongoose");
    
    mongoose
      .connect("mongodb://localhost/CurryCoder", {
        useNewUrlParser: true,
        useUnifiedTopology: true
      })
      .then(() => console.log("數(shù)據(jù)庫連接成功啦!"))
      .catch(err => console.log(err, "數(shù)據(jù)庫連接失敗啦!"));
    
1.8 創(chuàng)建數(shù)據(jù)庫
  • 在 mongoDB 中不需要顯式創(chuàng)建數(shù)據(jù)庫,如果正在使用的數(shù)據(jù)庫不存在,mongoDB 會自動創(chuàng)建

2.mongoDB 數(shù)據(jù)庫的增刪改查操作

2.1 創(chuàng)建集合
  • 創(chuàng)建集合分為兩步:

    • 首先,對集合設定規(guī)則。
    • 然后,創(chuàng)建集合。創(chuàng)建 mongoose.Schema 構(gòu)造函數(shù)的實例即可創(chuàng)建集合。
    const mongoose = require("mongoose");
    mongoose
      .connect("mongodb://localhost/course_demo", {
        useNewUrlParser: true,
        useUnifiedTopology: true
      })
      .then(() => console.log("數(shù)據(jù)庫連接成功"))
      .catch(err => console.log(err, "數(shù)據(jù)庫連接失敗"));
    
    // 設定集合規(guī)則
    const courseSchema = new mongoose.Schema({
      name: String,
      author: String,
      isPublished: Boolean
    });
    
    // 使用規(guī)則去創(chuàng)建集合
    // 參數(shù)1:集合名稱,參數(shù)2:集合規(guī)則
    const Course = mongoose.model("Course", courseSchema); // 數(shù)據(jù)庫中集合名稱實際為courses
    
    2.2 創(chuàng)建文檔
    • 創(chuàng)建文檔實際上是向集合中插入數(shù)據(jù)。分為兩步:
      • 首先,創(chuàng)建集合的實例;
      • 其次,調(diào)用實例對象下的 save()方法將數(shù)據(jù)保存到數(shù)據(jù)庫中。
    • 和數(shù)據(jù)庫相關(guān)的操作都是異步操作
  // 創(chuàng)建文檔--方法1
  const course = new Course({
    name: "JavaScript",
    author: "CurryCoder",
    isPublished: true
  });

  course.save();

  // 創(chuàng)建文檔--方法2
  Course.create(
    {
      name: "Python",
      author: "Pink老師",
      isPublished: true
    },
    (err, doc) => {
      // 錯誤對象
      console.log(err);
      // 當前插入的文檔
      console.log(doc);
    }
  );

  // 創(chuàng)建文檔--方法2支持異步函數(shù)的語法
  Course.create({
    name: "C++",
    author: "掃地僧",
    isPublished: false
  })
    .then(doc => console.log(doc))
    .catch(err => console.log(err))
2.3 mongoDB數(shù)據(jù)庫導入數(shù)據(jù)
  • 前提:找到mongodb數(shù)據(jù)庫的安裝目錄,將安裝目錄下的bin目錄添加到系統(tǒng)的環(huán)境變量中。
  • 導入數(shù)據(jù)語法:mongoimport -d 數(shù)據(jù)庫名 -c 集合名 --file 要導入的數(shù)據(jù)文件
      E:\前端開發(fā)\JavaScript\練習代碼\mongoDB>mongoimport -d course_demo -c users --file
      ./user.json
      2020-07-02T21:16:45.454+0800    connected to: localhost
      2020-07-02T21:16:45.558+0800    imported 6 documents
    
2.4 查詢文檔
  • 根據(jù)條件查找文檔(條件為空則查找所有文檔)
    const mongoose = require("mongoose");
    mongoose
      .connect("mongodb://localhost/course_demo", {
        // course_demo數(shù)據(jù)庫的名字
        useNewUrlParser: true,
        useUnifiedTopology: true
      })
      .then(() => console.log("數(shù)據(jù)庫連接成功"))
      .catch(err => console.log(err, "數(shù)據(jù)庫連接失敗"));
    
    // 設定集合規(guī)則
    const userSchema = new mongoose.Schema({
      name: String,
      age: Number,
      email: String,
      password: String,
      hobbies: [String]
    });
    
    // 使用規(guī)則去創(chuàng)建集合
    // 參數(shù)1:集合名稱,參數(shù)2:集合規(guī)則
    const User = mongoose.model("User", userSchema); // 數(shù)據(jù)庫中集合名稱實際為users
    
    // 查詢用戶集合中的所有文檔
    User.find().then(result => console.log(result));
    
    // 通過限制條件查找文檔
    User.find({ _id: '5c09f267aeb04b22f8460968' }).then(result => console.log(result));
    
    // findOne()方法返回一條文檔,默認返回當前集合中的第一條文檔
    User.findOne({ name: '李四' }).then(result => console.log(result));
    
    // 匹配大于 小于
    User.find({ age: { $gt: 20, $lt: 50 } }).then(result => console.log(result));
    
    // 匹配包含
    User.find({ hobbies: { $in: ['敲代碼'] } }).then(result => console.log(result));
    
    // 選擇要查詢的字段name email,不想查詢字段_id
    User.find().select('name email -_id').then(result => console.log(result));
    
    // 將數(shù)據(jù)按照年齡進行降序排列 -age
    User.find().select('age -_id').sort('-age').then(result => console.log(result));
    
    // skip跳過多少條數(shù)據(jù)  limit限制查詢數(shù)量
    User.find().skip(2).limit(3).then(result => console.log(result));
    
2.5 刪除文檔
  • 刪除文檔如下:
    const mongoose = require("mongoose");
    mongoose
      .connect("mongodb://localhost/course_demo", {
        // course_demo數(shù)據(jù)庫的名字
        useNewUrlParser: true,
        useUnifiedTopology: true
      })
      .then(() => console.log("數(shù)據(jù)庫連接成功"))
      .catch(err => console.log(err, "數(shù)據(jù)庫連接失敗"));
    
    // 設定集合規(guī)則
    const userSchema = new mongoose.Schema({
      name: String,
      age: Number,
      email: String,
      password: String,
      hobbies: [String]
    });
    
    // 使用規(guī)則去創(chuàng)建集合
    // 參數(shù)1:集合名稱,參數(shù)2:集合規(guī)則
    const User = mongoose.model("User", userSchema); // 數(shù)據(jù)庫中集合名稱實際為users
    
    // 刪除單個文檔
    // 如果查詢條件匹配了多個文檔,那么將會刪除第一個匹配的文檔
    User.findOneAndDelete({ _id: '5c09f236aeb04b22f8460967' })
        .then(result => console.log(result));
    
    // 刪除多個文檔
    User.deleteMany({}).then(result => console.log(result));
    
2.6 更新文檔
  • 更新單個文檔:
    User.updateOne({查詢條件}, {要更改的值}).then(result => console.log(result));
    
  • 更新多個文檔:
    User.updateMany({查詢條件}, {要更改的值}).then(result => console.log(result));
    
  • 示例程序如下所示:
    const mongoose = require("mongoose");
    mongoose
      .connect("mongodb://localhost/course_demo", {
        // course_demo數(shù)據(jù)庫的名字
        useNewUrlParser: true,
        useUnifiedTopology: true
      })
      .then(() => console.log("數(shù)據(jù)庫連接成功"))
      .catch(err => console.log(err, "數(shù)據(jù)庫連接失敗"));
    
    // 設定集合規(guī)則
    const userSchema = new mongoose.Schema({
      name: String,
      age: Number,
      email: String,
      password: String,
      hobbies: [String]
    });
    
    // 使用規(guī)則去創(chuàng)建集合
    // 參數(shù)1:集合名稱,參數(shù)2:集合規(guī)則
    const User = mongoose.model("User", userSchema); // 數(shù)據(jù)庫中集合名稱實際為users
    
    // 更新集合中的單個文檔
    User.updateOne({ name: '李四' }, { name: '葛二蛋' }).then(result => console.log(result));
    
    // 更新集合中的多個文檔
    // 如果查詢條件匹配了多個文檔,那么將會更新第一個匹配的文檔
    User.updateMany({}, { age: 56 }).then(result => console.log(result));
    
2.7 mongoose驗證
  • 在創(chuàng)建集合規(guī)則時,可以設置當前字段的驗證規(guī)則,驗證失敗就輸入插入失敗。
    • required:true 必傳字段
    • minlength:最小長度
    • maxlength:最大長度
    • min:數(shù)值最小為2
    • max:數(shù)值最大為100
    • enum: ['html', 'css', 'js']
    • trim: 去除字符串兩邊的空格
    • validate: 自定義驗證器
    • message: 自定義錯誤信息
    const mongoose = require('mongoose');
    
    mongoose.connect('mongodb://localhost/course_demo', {
            useNewUrlParser: true,
            useUnifiedTopology: true
    })
        .then(() => console.log('數(shù)據(jù)庫連接成功'))
        .catch(err => console.log(err, '數(shù)據(jù)庫連接失敗'));
    
    // mongoose驗證
    const postSchema = new mongoose.Schema({
        title: {
            type: String,
            // required: true 必傳字段
            // 驗證規(guī)則
            required: [true, '請傳入文章標題'],  
            // minlength: 2,
            minlength: [2, '文章長度不能小于2'],
            maxlength: 5,
            // 去除字符串兩端的空格
            trim: true
        },
        age: {
            type: Number,
            // 數(shù)字的最小范圍
            min: 18,
            // 數(shù)字的最大范圍
            max: [100, '年齡最大不超過100歲']
        },
        publishDate: {
            type: Date,
            // 默認值
            default: Date.now
        },
        category: {
            type: String,
            // 枚舉 列舉出當前字段可以擁有的值
            enum: {
                values:['html', 'css', 'js', 'python'],
                message: '分類名稱要在指定的范圍內(nèi)才可以'
            }
        },
        author: {
            type: String,
            validate: {
                validator: v => {
                    // 返回布爾值 true表示驗證成功,反之表示失敗 v表示要驗證的值
                    return v && v.length > 4;
                },
                // 自定義錯誤信息
                message: '傳入的值不符合驗證規(guī)則'
            }
        }
    });
    
    const Post = mongoose.model('Post', postSchema);
    Post.create({ title: 'aa', age: 30, category: 'C++', author: 'bd' }).then(result => console.log(result)).catch(error => {
        // 獲取錯誤信息對象
        const err = error.errors;
        // 循環(huán)錯誤信息對象
        for (let attr in err) {
            console.log(err[attr]['message']);
        }
    });
    
2.8 集合關(guān)聯(lián)
  • 通常不同集合的數(shù)據(jù)之間是有聯(lián)系的,例如文章信息和用戶信息分別存儲在不同的集合中,但文章是某個用戶發(fā)表的,要查詢文章的所有信息包括發(fā)表用戶,就要考慮到集合關(guān)聯(lián)。
    • 使用id對集合進行關(guān)聯(lián);
    • 使用populate()方法進行關(guān)聯(lián)集合查詢


      集合關(guān)聯(lián).png
    const mongoose = require('mongoose');
    
    mongoose.connect('mongodb://localhost/course_demo', {
        // course_demo數(shù)據(jù)庫的名字
        useNewUrlParser: true,
        useUnifiedTopology: true
    })
        .then(() => console.log('數(shù)據(jù)庫連接成功'))
        .catch(err => console.log(err, '數(shù)據(jù)庫連接失敗'));
    
    // 用戶集合規(guī)則
    const userSchema = new mongoose.Schema({
        name: {
            type: String,
            required: true
        }
    });
    
    // 文章集合規(guī)則
    const postSchema = new mongoose.Schema({
        title: {
            type: String
        },
        author: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User'
        }
    });
    
    // 用戶集合
    const User = mongoose.model('User', userSchema);
    // 文章集合
    const Post = mongoose.model('Post', postSchema);
    
    // 創(chuàng)建用戶
    // User.create({name: 'CurryCoder'}).then(result => console.log(result));
    // 創(chuàng)建文章
    // Post.create({ title: '我的第一篇blog', author: '5efee0fd1dd5be06b4e24a87' }).then(result => console.log(result));
    
    // 集合關(guān)聯(lián)
    Post.find({title: '我的第一篇blog'}).populate('author').then(result => console.log(result));
    
2.9 案例:用戶信息的增刪改查[代碼參見文末鏈接中的08_user文件夾]
  • (1).搭建網(wǎng)站服務器,實現(xiàn)客戶端與服務端的通信;
  • (2).連接數(shù)據(jù)庫,創(chuàng)建用戶集合,向集合中插入文檔;
  • (3).當用戶訪問/list時,將所有用戶信息查詢出來;
    • 實現(xiàn)路由功能;
    • 程序用戶列表頁面;
    • 從數(shù)據(jù)庫中查詢用戶信息,將用戶信息展示在列表中;
  • (4).將用戶信息和表格HTML進行拼接,并將結(jié)果響應返回給客戶端;
  • (5).當用戶訪問/add時,呈現(xiàn)表單頁面,并實現(xiàn)添加用戶信息的功能;
  • (6).當用戶訪問/modify時,呈現(xiàn)修改頁面,并實現(xiàn)修改用戶信息的功能;
    • 增加頁面路由呈現(xiàn)頁面
      • 在點擊修改按鈕時,將用戶ID傳遞到當前頁面
      • 從數(shù)據(jù)庫中查詢當前用戶的信息,將用戶信息展示到頁面中
    • 實現(xiàn)用戶信息修改功能
      • 指定表單的提交地址以及請求方式
      • 接收客戶端傳遞過來的修改信息,找到用戶將用戶信息修改為最新的
  • (7).當用戶訪問/delete時,實現(xiàn)用戶刪除功能;

3.資料下載

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容