最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 面向Node.js开发者的MongoDB教程 (1):MongoDB和Mongoose基础 - 掘金

    正文概述 掘金(熠辉)   2021-09-26   591

    教程说明

    本文是《面向Node.js开发者的MongoDB教程》的第一章,本教程大部分参考了《MongoDB权威指南(第二版)》,Kirstina Chodorow著(O'Reilly, 2013)。可权威指南中使用的MongoDB版本是2.4.x的。在实际写用户代码时,发现有些语法已经不可用了,本教程所使用的环境中MongoDB版本为5.0.x的最新版。并结合我自己是一名Node.js开发者,教程中应用内代码都是使用的Node.js + Mongoose编写。 ​

    安装MongoDB

    windows/Linux/MacOS等各个环境MongoDB的安装大家可以在MongoDB官网-《MongoDB社区下载》自行下载安装。本文我更加倾向于读者尝试使用Docker安装MongoDB,理由有两个: ​

    1. 简单: 只需要使用一行命令,就可以通过镜像运行一个MongoDB数据库的容器

    2. 易于调试: 教程中可能需要对同一份数据进行增删改查,使用Docker可以创建多个互不干扰的容器,方便调试对比。

    数据来源(B站热点)

    面向Node.js开发者的MongoDB教程 (1):MongoDB和Mongoose基础 - 掘金

    本次教程中数据库的数据,来源来自B站的“综合热门”的后端接口数据。笔者提供了25300条文档数据,方便之后的教程中用来进行数据的增删改查。下面取了一条数据库中的数据:

    {
        "_id" : ObjectId("6123b52a64ceb40e2917c933"),
        "videos" : 1,
        "tid" : 17,
        "desc" : "",
        "duration" : 1537,
        "aid" : 675061011,
        "tname" : "单机游戏",
        "copyright" : 1,
        "pic" : "http://i1.hdslb.com/bfs/archive/7b9bff6a7e31bc55fc6a80341a23c43225b5f24e.jpg",
        "title" : "三界四洲不可救【龙崎黑神话解析03】",
        "pubdate" : ISODate("1970-01-19T20:41:24.902Z"),
        "ctime" : ISODate("1970-01-19T20:41:24.902Z"),
        "state" : 0,
        "owner" : {
            "mid" : 4564056,
            "name" : "龙崎棒棒糖",
            "face" : "http://i0.hdslb.com/bfs/face/74b6d0663e92c0595c40033a1f3495aff7d27f4b.jpg"
        },
        "stat" : {
            "aid" : 675061011,
            "view" : 1255439,
            "danmaku" : 8719,
            "reply" : 6384,
            "favorite" : 30489,
            "coin" : 81238,
            "share" : 12405,
            "now_rank" : 0,
            "his_rank" : 46,
            "like" : 99243,
            "dislike" : 0
        },
        "dynamic" : "原本写了8000字文案,结果把自己累出病来了,就删了一千多字,途中电脑崩溃了一次,把写了一个半小时的文案和其他保存文件给搞没了,可以说是我有史以来最敢的一期视频,技术部分感谢沙滩大佬的传授",
        "cid" : 395060770,
        "dimension" : {
            "width" : 1920,
            "height" : 1080,
            "rotate" : 0
        },
        "short_link" : "https://b23.tv/BV18U4y1j765",
        "short_link_v2" : "https://b23.tv/BV18U4y1j765",
        "first_frame" : "http://i0.hdslb.com/bfs/storyff/n210823a22pk2invww0sv02xkt574ew8_firsti.jpg",
        "bvid" : "BV18U4y1j765",
        "season_type" : 0,
        "rcmd_reason" : {
            "content" : "百万播放",
            "corner_mark" : 0
        },
        "update_time" : ISODate("2021-08-23T14:48:10.392Z"),
        "__v" : 0
    }
    

    大家可以通过百度网盘下载我提供的数据文件bilihot.json,并导入到MongoDB中。

    使用mongoimport导入bilihot.json:

    $ mongoimport -d bilibili_hot -c hotspots --file /bilihot.json --type json
    

    参数说明:

    • -d: 数据库名称
    • -c: 集合名称
    • --file: 要导入的文件路径
    • --type: 导入的文件类型,默认为json

    建议使用云服务器

    对于大部分前端开发者而言,不仅建议在本地跑一遍相关代码,更加建议自己购买一个云服务器,安装MongoDB后使用远程命令行连接运行一遍。这样有利于学习Linux相关命令、适应后端运行环境。 ​

    面向Node.js开发者的MongoDB教程 (1):MongoDB和Mongoose基础 - 掘金 阿里云-云服务器最新优惠活动地址

    MongoDB基础

    数据库

    在MongoDB中,多个文档组成集合,而多个集合可以组成数据库。一个MongoDB实例可以承载多个数据库,每个数据库拥有0个或者多个集合。每个数据库都有独立的权限,即便是在磁盘上,不同的数据库也放置在不同的文件中。 ​

    在MongoDB中,我们可以使用use db_name来切换数据库,例如本教程中我们的数据库名称为bilibili_hot,那么你可以通过以下命令进入到该数据库。

    > use bilibili_hot
    

    文档

    文档(document)是MongoDB中的核心概念,如果你熟悉MySQL等关系型数据库,你可以将文档比喻为一行。文档在JavaScript文档被表示为为对象,例如刚才存入数据库中的一条B站热点数据就是一个文档:

    {
      "title" : "三界四洲不可救【龙崎黑神话解析03】"
      "pubdate" : ISODate("1970-01-19T20:41:24.902Z"),
      "ctime" : ISODate("1970-01-19T20:41:24.902Z"),
      "duration" : 1537,
      ...
    }
    

    MongoDB的文档区分类型和大小写,并且不能有重复的key,这和JavaScrit中对象的概念基本一致,对于Node.js开发者来说很好理解。例如下面两个文档就是不同的:

    {
      "title" : "三界四洲不可救【龙崎黑神话解析03】"
    }
    
    {
      "Title" : "三界四洲不可救【龙崎黑神话解析03】"
    }
    
    

    下面两个文档也是不同的:

    {
    	"duration" : 1537
    }
    
    {
    	"duration" : "1537"
    }
    

    集合

    集合(collection)就是一组文档,一个或多个集合组成了一个MongooDB的数据库,我们可以将集合比喻为关系型数据库中的一张表。

    集合的英文单词是collection,这个单词在MongoDB的操作中经常会使用到:

    • 例如显示所有的集合:
    > show collections
    
    • 创建集合statistics
    > db.createCollection('statistics')
    
    • 查询hotspots集合中的全部文档数据:
    > db.getCollection('hotspots').find({})
    

    MongoDB中的集合是动态模式,这意味着集合中的文档的结构和类型可以是各式各样的,下面两个文档是可以放在同一个集合中,一个文档存的是视频的名称,一个文档存的是视频的播放次数。

    { "title": "三界四洲不可救【龙崎黑神话解析03】" },
    { "view": 1280 }
    

    上面的两个文档,不仅是值的类型不一致,同时键也不一致。作为一名有经验的程序员,肯定不会在集合中这样去组织文档。针对上面的的情况,我们建议使用不同的集合去存储视频的基本信息和视频的统计信息(播放数、点赞数、投币数等)

    mongod

    启动MongoDB 在命令行执行mongod,即可启动MongoDB服务器,mongod在启动时可以使用许多可配置项,下面列举几个常用的:

    $ mongod
    
    • --dbpath: 指定一个目录作为数据目录,其默认目录为/data/db
    • --port: 指定服务器监听的端口号,mongod默认占用27017端口
    • --fork:调用fork创建子进程,在后台运行MongoDB。启用--fork时,必须同时启用--logpath
    • --logpath:指定文件作为输出信息的文件,而非在命令行上输出。
    • --config:额外加载配置文件,未在命令行中指定的选项将使用配置文件中的从参数。

    停止MongoDB 关闭运行中的服务器的命令是一个管理员命令,首先我们需要在Mongo Shell中切换到admin数据库。

    > use admin
    

    再使用db.shutdownServer()

    > db.shutdownServer()
    

    mongo

    在命令行执行mongo,可以启动mongosh(又称MongoDB Shell),它是我们学习MongoDB最重要的工具,绝大多数的MongoDB操作都需要使用shell完成。在运行mongo前,请先执行mongod运行MongoDB服务器,之后shell将自动连接到MongoDB服务器。

    $ mongo
    
    MongoDB server version: 5.0.2
    ---
    > 
    

    shell是一个独立的MongoDB客户端,启动时,shell会连接到MongoDB服务器的test数据库我们可以使用db命令查看当前使用了哪个数据库:

    • 查看当前数据库db
    > db
    test
    
    • 查看目前所有的数据库show dbs
    > show dbs
    admin         0.000GB
    bilibili_hot  0.015GB
    config        0.000GB
    local         0.000GB
    
    • 使用某一个数据库use 数据库名, 例如使用bilibili_hot数据库
    > use bilibili_hot
    switched to db bilibili_hot
    

    CRUD

    创建文档

    insert()方法用于把文档插入集合中,我们把一条数据插入到hotspots集合下

    > db.hotspots.insert({
        videos: 1,
        tid: 17,
        desc: "",
        duration: 1537,
        aid: 675061011,
        tname: "单机游戏",
        copyright: 1,
        pic: "http://i1.hdslb.com/bfs/archive/7b9bff6a7e31bc55fc6a80341a23c43225b5f24e.jpg",
        title: "三界四洲不可救【龙崎黑神话解析03】(新增)",
        pubdate: new Date("1970-01-19T20:41:24.902Z"),
        ctime: new Date("1970-01-19T20:41:24.902Z"),
        state: 0,
        owner: {
          mid: 4564056,
          name: "龙崎棒棒糖",
          face: "http://i0.hdslb.com/bfs/face/74b6d0663e92c0595c40033a1f3495aff7d27f4b.jpg",
        },
        stat: {
          aid: 675061011,
          view: 1255439,
          danmaku: 8719,
          reply: 6384,
          favorite: 30489,
          coin: 81238,
          share: 12405,
          now_rank: 0,
          his_rank: 46,
          like: 99243,
          dislike: 0,
        },
        dynamic:
          "原本写了8000字文案,结果把自己累出病来了,就删了一千多字,途中电脑崩溃了一次,把写了一个半小时的文案和其他保存文件给搞没了,可以说是我有史以来最敢的一期视频,技术部分感谢沙滩大佬的传授",
        cid: 395060770,
        dimension: {
          width: 1920,
          height: 1080,
          rotate: 0,
        },
        short_link: "https://b23.tv/BV18U4y1j765",
        short_link_v2: "https://b23.tv/BV18U4y1j765",
        first_frame:
          "http://i0.hdslb.com/bfs/storyff/n210823a22pk2invww0sv02xkt574ew8_firsti.jpg",
        bvid: "BV18U4y1j765",
        season_type: 0,
        rcmd_reason: {
          content: "百万播放",
          corner_mark: 0,
        },
        update_time: new Date("2021-08-23T14:48:10.392Z")
     })
    

    查询文档

    find()方法用于查询集合中的文档,如果想查询一个文档,可用findOne()。我们来找到刚才新增的那一个文档:

    > db.hotspots.findOne({ title: '三界四洲不可救【龙崎黑神话解析03】(新增)' })
    

    修改文档

    update()方法用来修改文档,我们来改变刚才新增的那个文档的title字段:

    > db.hotspots.update(
      { title: "三界四洲不可救【龙崎黑神话解析03】(新增)" },
      { $set: { title: "三界四洲不可救【龙崎黑神话解析03】(最新新增)" } }
    )
    

    删除文档

    remove()方法用来将文档从集合中永久移除,我们来把刚才更改过的那条文档给删除掉:

    > db.hotspots.remove({ title: '三界四洲不可救【龙崎黑神话解析03】(最新新增)' })
    

    Mongoose基础

    Mongoose是在node环境中MongoDB数据库操作的封装,一个对象模型工具。将数据库中的数据转换为JavaScript对象以方便我们在应用中使用。

    安装Mongoose

    npm install mongoose --save
    

    Connection

    你可以使用mongoose.connect()方法连接到MongoDB:

    const mongoose = require("mongoose");
    
    mongoose
      .connect("mongodb://127.0.0.1:27019/bilibili_hot", { useNewUrlParser: true })
      .then(() => console.log("MongoDB Connected"))
      .catch((err) => console.log(err));
    

    该方法的第1个参数是MongoDB的连接地址,第2个参数是一个options对象,该对象会被Mongoose传递给MongoDB的驱动程序,你可以在《MongoDB Node.js驱动程序文档》中找到完成的options的配置项, 下面是一些比较重要的配置项:

    • user/pass: 用于认证的用户名和密码。Mongoose 特有,等价于 MongoDB 驱动的auth.userauth.password选项。
    • useFindAndModify:默认为true,设置为false会让findOneAndUpdate()findOneAndRemove()使用findOneAndUpdate()而不是findAndModify()
    • poolSize:MongoDB 驱动程序将为此连接保持打开的最大套接字数。默认情况下,poolSize是5。
    • useNewUrlParser:底层 MongoDB 驱动程序已弃用其当前的连接字符串解析器。因为这是一个重大变化,他们添加了一个useNewUrlParser标志,允许用户在发现新解析器中的错误时回退到旧解析器。你应该设置,useNewUrlParser: true

    Schema

    Schema是Mongoose中的重要概念,Schema定义了集合中文档的结构。结合上文提到的数据库的数据,我们定义的Schema如下所示:

    // HotSpot.js
    
    const mongoose = require("mongoose");
    const Schema = mongoose.Schema;
    
    const hotSpotSchema = new Schema({
      aid: {
        type: Number,
        required: true,
      },
      videos: {
        type: Number,
        default: 1,
      },
      tid: {
        type: Number,
        default: 0,
      },
      tname: {
        type: String,
        require: true,
      },
      copyright: {
        type: Number,
        dafault: 1,
      },
      pic: {
        type: String,
      },
      title: {
        type: String,
        require: true,
      },
      pubdate: {
        type: Date,
      },
      ctime: {
        type: Date,
        require: true,
      },
      desc: {
        type: String,
        default: "",
      },
      state: {
        type: Number,
      },
      duration: {
        type: Number,
        default: 0,
      },
      owner: {
        mid: {
          type: Number,
        },
        name: {
          type: String,
        },
        face: {
          type: String,
        },
      },
      stat: {
        aid: {
          type: Number,
        },
        view: {
          type: Number,
        },
        danmaku: {
          type: Number,
        },
        reply: {
          type: Number,
        },
        favorite: {
          type: Number,
        },
        coin: {
          type: Number,
        },
        share: {
          type: Number,
        },
        now_rank: {
          type: Number,
        },
        his_rank: {
          type: Number,
        },
        like: {
          type: Number,
        },
        dislike: {
          type: Number,
        },
      },
      dynamic: {
        type: String,
      },
      cid: {
        type: Number,
      },
      dimension: {
        width: {
          type: Number,
        },
        height: {
          type: Number,
        },
        rotate: {
          type: Number,
        },
      },
      short_link: {
        type: String,
      },
      short_link_v2: {
        type: String,
      },
      first_frame: {
        type: String,
      },
      bvid: {
        type: String,
      },
      season_type: {
        type: Number,
      },
      rcmd_reason: {
        content: {
          type: String,
        },
        corner_mark: {
          type: Number,
        },
      },
      update_time: {
        type: Date,
      },
    });
    

    Model

    Model是从Schema编译来的构造函数,这也就是为什么这里需要使用大写字母开头的原因。Model负责从MongoDB中创建和读取文档。

    当你调用mongoose.model()是时,Mongoose就会为你编译一个Model

    const HotSpot = mongoose.model("hotSpot", hotSpotSchema);
    
    • 参数1: 是collection的单数名称,也就是说,当你的数据库中没有任何集合的时候,当你使用Mongoose连接到MongoDB,并准备插入数据时,Mongoose会自动为你创建一个叫hotspots的集合。
    • 参数2: 调用new Schema所创建的Schema

    CRUD

    创建好Model后,你就可以使用Model对应的方法操作集合中的文档了,这里我们简单的介绍一下使用Mongoose中的CRUD方法。

    创建文档

    你可以使用Model.create() 创建一条文档数据:

     const newVideo = {
        videos: 1,
        tid: 17,
        desc: "",
        duration: 1537,
        aid: 675061011,
        tname: "单机游戏",
        copyright: 1,
        pic: "http://i1.hdslb.com/bfs/archive/7b9bff6a7e31bc55fc6a80341a23c43225b5f24e.jpg",
        title: "三界四洲不可救【龙崎黑神话解析03】(新增)",
        pubdate: new Date("1970-01-19T20:41:24.902Z"),
        ctime: new Date("1970-01-19T20:41:24.902Z"),
        state: 0,
        owner: {
          mid: 4564056,
          name: "龙崎棒棒糖",
          face: "http://i0.hdslb.com/bfs/face/74b6d0663e92c0595c40033a1f3495aff7d27f4b.jpg",
        },
        stat: {
          aid: 675061011,
          view: 1255439,
          danmaku: 8719,
          reply: 6384,
          favorite: 30489,
          coin: 81238,
          share: 12405,
          now_rank: 0,
          his_rank: 46,
          like: 99243,
          dislike: 0,
        },
        dynamic:
          "原本写了8000字文案,结果把自己累出病来了,就删了一千多字,途中电脑崩溃了一次,把写了一个半小时的文案和其他保存文件给搞没了,可以说是我有史以来最敢的一期视频,技术部分感谢沙滩大佬的传授",
        cid: 395060770,
        dimension: {
          width: 1920,
          height: 1080,
          rotate: 0,
        },
        short_link: "https://b23.tv/BV18U4y1j765",
        short_link_v2: "https://b23.tv/BV18U4y1j765",
        first_frame:
          "http://i0.hdslb.com/bfs/storyff/n210823a22pk2invww0sv02xkt574ew8_firsti.jpg",
        bvid: "BV18U4y1j765",
        season_type: 0,
        rcmd_reason: {
          content: "百万播放",
          corner_mark: 0,
        },
        update_time: new Date("2021-08-23T14:48:10.392Z")
      };
    
    
      HotSpot.create(newVideo, function (err, video) {
        if (err) {
          console.log(err);
          return;
        }
        console.log(video)
      });
    

    查询文档

    查询的方法有很多,目前我们只介绍Model.find(),让我们来查询刚才新增的那一条数据吧:

    HotSpot.find({ title: '三界四洲不可救【龙崎黑神话解析03】(新增)'}, function(err, videos) {
      if (err) {
        console.log(err)
        return
      }
      console.log(videos)
    })
    

    修改文档

    我们可以使用Model.updateOne()更新数据库中的文档

    HotSpot.updateOne(
      { title: "三界四洲不可救【龙崎黑神话解析03】(新增)" },
      { $set: { title: "三界四洲不可救【龙崎黑神话解析03】(最新新增)" } },
      function (err, raw) {
        if (err) {
          console.log(err);
          return;
        }
        console.log(raw);
      }
    );
    

    删除文档

    让我们使用Model.deleteOne()删除刚才更改的文档吧,把我们的数据库恢复原貌:

    const raw = await HotSpot.deleteOne({ title: "三界四洲不可救【龙崎黑神话解析03】(最新新增)" });
    
    console.log(raw)
    

    Mongoose总结

    在想使用Mongoose来对MongoDB进行操作前,需要先进行三步操作,分别是:

    • 连接MongoDB
    • 生成Schema
    • 生成Model

    然后在Model中可以进行相应的CRUD操作

    const mongoose = require("mongoose");
    const hotSpotSchema = new Schema({...}) // 生成Schmea
    const HotSpot = mongoose.model("hotSpot", hotSpotSchema); // 生成Model
    
    // 连接MongoDB
    mongoose
      .connect("mongodb://127.0.0.1:27019/bilibili_hot", { useNewUrlParser: true })
      .then(() => console.log("MongoDB Connected"))
      .catch((err) => console.log(err));
    
    // 数据库CRUD操作
    HotSpot.findOne({ ... })
    

    其他

    1. 使用Docker安装MongoDB

    运行MongoDB容器 使用下面命令运行一个mongo容器,如果你本地没有找到mongo的镜像,那么docker会自动拉取远程镜像,可能会耗时比较长。

    $ docker run -p 27019:27017 --name mymongo -v ~/db:/data/db -d mongo
    

    参数说明:

    • -p: 端口映射,-p 27019:27017是指将容器内27017端口映射到宿主机的27019端口
    • --name:容器命名,--name mymongo 将该运行中的容器命名为mymongo
    • -v: 数据卷,-v ~/db:/data/db 将容器内存放数据的/data/db目录映射到宿主机的~/db目录上

    查看容器运行状态 使用docker ps命令查看容器的运行状态

    $ docker ps 
    
    CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                                           NAMES
    ddfc4fd875e6   mongo     "docker-entrypoint.s…"   4 minutes ago   Up 4 minutes   0.0.0.0:27019->27017/tcp, :::27019->27017/tcp   mymongo
    

    进入容器内并进入bash操作 我们可以使用docker exec进入容器内,调式MongoDB。需要注意的是,ddfc4fd875e6是上一步执行docker ps命令显示的CONTAINER ID,读者的值肯定和笔者的不一致,需替换成自己的CONTAINER ID

    $ docker exec -it ddfc4fd875e6 /bin/bash
    
    root@ddfc4fd875e6:/# 
    

    上面表示已经进入到了容器内部,我们来查看一下MongoDB的版本,在命令行输入mongo进入MongoDB shell。

    root@ddfc4fd875e6:/# mongo
    

    此时进入到了MongoDB shell中,我们就可以执行相应操作了

    # 查看MongoDB版本
    > db.version()
    5.0.2
    
    # 显示数据库
    > show dbs
    admin   0.000GB
    config  0.000GB
    local   0.000GB
    

    退出shell和容器

    # 输入exit回车 退出MongoDB shell
    > exit
    bye
    
    # 输入exit回车,退出容器
    root@ddfc4fd875e6:/# exit
    exit
    

    2. 参考文献

    1. Mongoose官网
    2. MongoDB官网

    起源地下载网 » 面向Node.js开发者的MongoDB教程 (1):MongoDB和Mongoose基础 - 掘金

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元