专业编程基础技术教程

网站首页 > 基础教程 正文

MongoDB 从入门到精通 mongodb入门教程

ccvgpt 2024-10-29 13:20:05 基础教程 8 ℃

本文的思维导图如下所示:

什么是 MongoDB

MongoDB 是由 C++ 编写的一个数据库,是一个分布式超出的开源数据库系统。在高负载的情况下,表现的成绩要比 MySql 更好,MongoDB 可以为 WEB 应用提供可扩展的高性能数据库解决方案。MongoDB 将数据存储为一个文档,数据结构是由键值对组成的,MongoDB 文档类似于 JSON 对象,字段值可以包含其他文档,数组或者其他文档数据。

MongoDB 从入门到精通 mongodb入门教程

其具有以下的特点:

  • MongoDB 是一个面向对象的数据库,操作起来更加的快。
  • 可以在 MongoDB 中记录任何属性的索引,实现更快的排序。
  • 可以在本地或者网络中创建镜像。
  • 如果负载增加,可以在分布式计算机中增加更多的分片。
  • MongoDB 支持丰富的表达式,查询指令可以使用 JSON 完成标记,可以在文档中查询对象和数组。
  • MongoDB 可以使用 update 命令实现替换完成的文档,或者指定一些数据字段。
  • MongoDB 中 Map 和 reauce 主要用来对数据进行处理。
  • Map 函数和 Reduce 都是由 Js 编写而成的。
  • GridFS 是 MongoDB 中内置的一个功能,可以存储小文件。
  • MongoDB 允许在服务端执行脚本,可以用 Js 编写某个函数,直接在服务器端执行。
  • MongoDB 支持各种编程语言。
  • MongoDB 安装相当简单。

MongoDB 安装

Windows

进入地址,下载 MongoDB:

https://www.mongodb.com/download-center/community

下载完成文件,按照操作步骤直接安装即可。

若要运行 MongoDB,需要打开 PowerShell 执行以下命令:

C:\mongodb\bin\mongod --dbpath c:\data\db

若执行成功,将会输出以下内容:

2015-09-25T15:54:09.212+0800 I CONTROL  Hotfix KB2731284 or later update is not
installed, will zero-out data files
2015-09-25T15:54:09.229+0800 I JOURNAL  [initandlisten] journal dir=c:\data\db\j
ournal
2015-09-25T15:54:09.237+0800 I JOURNAL  [initandlisten] recover : no journal fil
es present, no recovery needed
2015-09-25T15:54:09.290+0800 I JOURNAL  [durability] Durability thread started
2015-09-25T15:54:09.294+0800 I CONTROL  [initandlisten] MongoDB starting : pid=2
488 port=27017 dbpath=c:\data\db 64-bit host=WIN-1VONBJOCE88
2015-09-25T15:54:09.296+0800 I CONTROL  [initandlisten] targetMinOS: Windows 7/W
indows Server 2008 R2
2015-09-25T15:54:09.298+0800 I CONTROL  [initandlisten] db version v3.0.6

若要进入 MongoDB,需要输入如下命令,进入 MongoDB 命令行界面。

C:\mongodb\bin\mongo.exe

Linux

输入命令,下载相关的安装包。

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz    ### 下载

解压:

tar -zxvf mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz                                    ### 解压

将解压包,拷贝到执行目录。

mv mongodb-src-r4.2.8  /usr/local/mongodb4                          ### 将解压包拷贝到指定目录

将其添加到 PATH 目录中。

export PATH=<mongodb-install-directory>/bin:$PATH

创建相关目录,并初始化权限。

sudo mkdir -p /var/lib/mongo
sudo mkdir -p /var/log/mongodb
sudo chown `whoami` /var/lib/mongo     ### 设置权限
sudo chown `whoami` /var/log/mongodb   ### 设置权限

启动 MongoDB 服务。

mongod --dbpath /var/lib/mongo --logpath /var/log/mongodb/mongod.log --fork

若要进入 MongoDB,需要输入如下命令。

$ cd /usr/local/mongodb4/bin
$ ./mongo
MongoDB shell version v4.2.8
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("2cfdafc4-dd56-4cfc-933a-187b887119b3") }
MongoDB server version: 4.2.8
Welcome to the MongoDB shell.
……

MongoDB 集合操作

查看集合

查看数据库中的集合。

>show collections
teams
users
……

查看文档中所有集合的名称:

> db.getCollectionNames()
[
    "teams",
    "users",
    ……
]

查看单个集合的名称。

> db.getCollection("users")
newDB.users

创建集合

使用 createCollection 创建集合

创建集合,使用下方的函数:

db.createCollection(name, options)
  • name:String,要创建的集合名
  • options:capped:是否启用限制集合。autoIndexID:是否自动创建索引字段size:限制集合大小max:允许最大文档数

例子:

> db.createCollection("student")
{ "ok" : 1 }

使用 insert 创建集合

> db.sites.insert({name:"itbilu.com"})
WriteResult({ "nInserted" : 1 })
> show collections
sites
student
teams
users
……

集合重名名

db.COLLECTION_NAME.renameCollection("NEW_NAME")

将 student 重命名为 students:

> db.student.renameCollection("students")
{ "ok" : 1 }
> show collections
sites
students
teams
users
……

集合的删除

db.COLLECTION_NAME.drop()

删除 students 集合

> db.students.drop()
true
> show collections
sites
teams
users
……

MongoDB 文档操作

文档创建和数据插入

MongoDB 插入数据使用如下的 API:

db.tests.insert({"foo":"foo"})

插入多个数据,使用如下的 API:

db.tests.insert({"_id":0}, {"_id":1}, {"_id":0})

文档更新

修改 API 如下所示:

update(query, update)

文档替换

文档替换是用一个新文档,替换一个完全匹配的文档。

{ "_id" : 1, "name" : "liuht", "blog" : "itbilu.com" }

替换的语句如下所示:

db.tests.update({'_id':1}, {name:'ht'})

修改器使用

set 修改器

set 修改器用于指定一个字段的值,当字段不存在的时候,会自动进行添加该字段的值。

> db.tests.update({'_id':1}, { $set: { name:'liuht', age:30 }})
> db.tests.find({ _id: 1})
{ "_id" : 1, "name" : "liuht", "age" : 30 }

修改错误,或者不在需要的字段,可以使用 unset 方法删除

> db.tests.update({'_id':1}, { $unset:{age:30}})
> db.tests.find({ _id: 1})
{ "_id" : 1, "name" : "liuht" }

set 修改器,也可以用于修改内嵌文档

> db.tests.find({ _id: 1})
{ "_id" : 1, "name" : { "firstName" : "liu", "lastName" : "ht" } }
> db.tests.update({'_id':1}, { $set:{ 'name.lastName':'tt' }})
> db.tests.find({ _id: 1})
{ "_id" : 1, "name" : { "firstName" : "liu", "lastName" : "tt" } }

Inc 修改器

Inc 修改器,用于字段值的增加和减少。

{ "_id" : 1, "name" : "liuht", "age" : 30 }
> db.tests.update({'_id':1}, { $inc:{ age: 1 }})
> db.tests.find({ _id: 1})
{ "_id" : 1, "name" : "liuht", "age" : 31 }

添加元素

对于已经存在的数组元素,使用 push 修改器,向数组添加元素。

> db.tests.update({'_id':1}, { $push:{ firends: 'sandy' }})
> db.tests.find({ _id: 1})
{ "_id" : 1, "name" : "liuht", "age" : 31, "firends" : [ "sandy" ] }

如果需要向数据添加多个值,可以使用 each 配合 push:

> db.tests.update({'_id':1}, { $push: {firends: { $each: ['sandy', 'andy'] }}})
> db.tests.find({ _id: 1})
{ "_id" : 1, "name" : "liuht", "age" : 31, "firends" : [ "sandy", "sandy", "andy" ] }

如果希望数组元素是定长的,可以使用 slice 配合 push 修改器。

> db.tests.update({'_id':1}, { $push: {firends: { 
                                          $each: ['sandy', 'andy'],
                                          $slice: -10 }}})

数组元素删除

数组元素删除,可以使用 pop 删除一个元素。

//从末尾删除
{ '$pop': { 'key': 1 } }
//从开头删除
{ '$pop': { 'key': -1 } }

数组元素修改

数组元素修改,可以使用 0 开始进行修改。

> db.blog.posts.findOne()
{ "_id": 1, 
  "content": "……",
  "comments": [
    { "comment": "one",
      "author": "andy" },
    { "comment": "two",
      "author": "sandy" },
    { "comment": "three",
      "author": "cat" }
  ]}

文档删除

db.tests.remove()   //删除集中所有数据
db.tests.remove({"_id":{$gt:10}})  //只有_id 大于 10 的文档才会删除

MongoDB 高级查询

基本查询

比较运算

等于

  • $lt:Less Than
  • $gt:Greater Than
  • $gte:Greater Than or Equal
  • $ne:Not Equal
### age 大于等于 18
db.mycollection1.find( { age:{$gt: 18} } )

逻辑运算

db.mycollection1.find( {
    $or: [
        { age: {$gte: 20} },
        { salary: {$gt: 5000} },
        { job: "HR" }
    ]
} )

范围运算

db.mycollection1.find( {
    age: {
        $in: [10, 20, 30]
    }
} )

正则表达式

db.mycollection1.find( {
    name: /^Ja\w+$/
} )

### 或
db.mycollection1.find( {
    name: {
        $regex: "/^Jaso\w?#34;
    }
} )

limit 和 skip

### 限定显示条数
db.mycollection1.find().limit(数量)

### 跳过指定第几条数据
db.mycollection1.find().skip(2)

### 混合使用
db.mycollection1.find().limit(10).skip(3)

自定义函数查询

db.mycollection1.find( {
    $where: function() {
        return this.age >= 18;
    }
} )

投影

### 格式为:
db.mycollection1.find(
    {查询条件},
    {显示与否的选项}
)

### 如:
db.mycollection1.find(
    {},
    { _id: 0, name: 1, age: 1 }
)

排序

db.mycollection1.find().sort({ name:1, age:-1 })

统计

db.mycollection1.find().count()

db.mycollection1.count( {查询条件} )

消除重复

### 格式为:
db.集合名.distinct( "指定字段", {查询条件} )

### 如
db.mycollection1.distinct( 
    "job", 
    { age: {$lt: 40} } 
)

管道聚合

常用的管道有:

  • $match:简单的根据条件过滤筛选
  • $group:将数据分组,一般配合一些统计函数,如$sum。
  • $project:修改 document 的结构。如增删改,或创建计算结果
  • $lookup
  • $unwind:将 List 列表类型的 Document 进行拆分
  • $sort
  • $limit
  • $skip

语法格式:

db.集合名.aggregate( [
    {管道表达式 1},
    {管道表达式 2},
    {管道表达式 2}
] )

例子:

db.Orders.aggregate( [
    {$match: {
        status: "A"
    } },
    {$group: {
        _id: "$cut_id",
        total: { $sum: "$amount" }
    } }
] )

Node.js 使用 MongoDB

安装 Express 框架:

npm install express-generator -g

初始化项目:

$ express testmongodb
// 初始化一个项目

安装相关依赖:

cd testmongodb
npm install

启动项目:

npm start

更改目录结构:

| bin
| modle
    - db.js
| config
    - config.js
| views
| public
| routes
    - index.js
| app.js
| package.json

安装 MongoDB:

npm install mongodb ---save

配置相关依赖:

// config.js
var baseUrl = "mongodb://localhost:27017";
var dbbase = "/mongodb_demo"; // 这里是我的数据库名称哦
module.exports = {
  "dburl": baseUrl + dbbase
};

对数据库操作:

// db.js
/**
 *  数据库封装
 * 
 */

var MongodbClient = require('mongodb').MongoClient
var assert = require('assert')
var config = require('../config/config.js')

/**
 * 连接数据库
 */

function __connectDB(callback) {
  MongodbClient.connect(config.dburl, function (err, db) {
    callback(err, db)
  })
}


/**
 * 插入一条数据
 * @param {*} collectionName 集合名
 * @param {*} Datajson 写入的 json 数据
 * @param {*} callback 回调函数
 */
function __insertOne(collectionName, Datajson, callback) {
  __connectDB(function (err, db) {
    var collection = db.collection(collectionName);
    collection.insertOne(Datajson, function (err, result) {
      callback(err, result); // 通过回调函数上传数据
      db.close();
    })
  })
}

/**
 * 查找数据
 * @param {*} collectionName 集合名
 * @param {*} Datajson 查询条件
 * @param {*} callback 回调函数
 */

function __find(collectionName, JsonObj, callback) {
  var result = [];
  if (arguments.length != 3) {
    callback("find 函数必须传入三个参数哦", null)
    return
  }
  __connectDB(function (err, db) {
    var cursor = db.collection(collectionName).find(JsonObj);
    if (!err) {
      cursor.each(function (err, doc) {
        assert.equal(err, null) // 使用 node 的 assert 模块来判断是否出错了
        // 如果出错了,那么下面的也将不会执行了
        if (doc != null) {
          result.push(doc)
        } else {
          callback(null, result)
          db.close();
        }
      })
    }
  })
}

/**
 * 
 * 删除数据(删除满足条件的所有数据哦)
 * @param {*} collectionName 集合名
 * @param {*} json 查询的 json 数据
 * @param {*} callback 回调函数
 */

function __DeleteMany(collectionName, json, callback) {
  __connectDB(function (err, db) {
    assert.equal(err, null)
    //删除
    db.collection(collectionName).deleteMany(
      json,
      function (err, results) {
        assert.equal(err, null)
        callback(err, results);
        db.close(); //关闭数据库
      }
    );
  });
}


/**
 * 修改数据
 * @param {*} collectionName 集合名
 * @param {*} json1 查询的对象
 * @param {*} json2 修改
 * @param {*} callback 回调函数
 */

function __updateMany(collectionName, json1, json2, callback) {
  __connectDB(function (err, db) {
    assert.equal(err, null)
    db.collection(collectionName).updateMany(
      json1,
      json2,
      function (err, results) {
        assert.equal(err, null)
        callback(err, results)
        db.close()
      }
    )
  })
}


/**
 * 获取总数
 * @param {*} collectionName 集合名
 * @param {*} json 查询条件
 * @param {*} callback 回调函数
 */

function __getCount(collectionName, json, callback) {
  __connectDB(function (err, db) {
    db.collection(collectionName).count(json).then(function (count) {
      callback(count)
      db.close();
    })
  })
}


/**
 * 分页查找数据
 * @param {*} collectionName 集合名
 * @param {*} JsonObj 查询条件
 * @param {*} C 【可选】传入的参数,每页的个数、显示第几页
 * @param {*} C  callback
 */

function __findByPage(collectionName, JsonObj, C, D) {
  var result = []; //结果数组
  if (arguments.length == 3) {
      //那么参数 C 就是 callback,参数 D 没有传。
      var callback = C;
      var skipnumber = 0;
      //数目限制
      var limit = 0;
  } else if (arguments.length == 4) {
      var callback = D;
      var args = C;
      //应该省略的条数
      var skipnumber = args.pageamount * args.page || 0;
      //数目限制
      var limit = args.pageamount || 0;
      //排序方式
      var sort = args.sort || {};
  } else {
      throw new Error("find 函数的参数个数,必须是 3 个,或者 4 个。");
      return;
  }

  //连接数据库,连接之后查找所有
  __connectDB(function (err, db) {
      var cursor = db.collection(collectionName).find(JsonObj).skip(skipnumber).limit(limit).sort(sort);
      cursor.each(function (err, doc) {
          if (err) {
              callback(err, null);
              db.close(); //关闭数据库
              return;
          }
          if (doc != null) {
              result.push(doc); //放入结果数组
          } else {
              //遍历结束,没有更多的文档了
              callback(null, result);
              db.close(); //关闭数据库
          }
      });
  });
}


module.exports = {
  __connectDB,
  __insertOne,
  __find,
  __DeleteMany,
  __updateMany,
  __getCount,
  __findByPage
}
// db.js 文件是数据库操作的 DAO 层的封装

配置 app.js:

//app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// 修改【1】 
global.db = require('./modle/db.js')    // 引入数据库封装好的 DAO 层方法 
var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// 修改【2】 这里配置我们的路由
app.use('/', indexRouter)
app.use('/users', usersRouter)
app.use('/testconnect', indexRouter)
app.use('/testdeletemany', indexRouter)
app.use('/testupdatemany', indexRouter)
app.use('/count', indexRouter)
app.use('/testfingbypage', indexRouter)


// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

配置 index.js:

// index.js
// 这里用来配置路由操作
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function (req, res, next) {
  res.render('index', { title: 'Express' });
});

// 测试数据库连接
router.get('/testconnect', function (req, res) {
  global.db.__connectDB(function (err, db) {
    if (err) {
      console.log(err)
      return
    }
    console.log(db)
    res.render('index', { title: '连接数据库成功' })
  })
})

// 测试插入数据
router.get('/testinsert', function (req, res) {
  global.db.__insertOne('student', {
    "name": "zjj",
    "age": 33,
    "interests": ['play'],
    "sex": "男"
  }, function (err, result) {
    if (!err) {
      console.log(result)
      res.render('index', { title: '插入一条数据成功' })
    } else {
      console.log(err)
    }
  })
})

// 查找数据
router.get('/testfind', function (req, res) {
  global.db.__find('student', { age: { $lt: 30 } }, function (err, result) {
    if (!err) {
      console.log(result)
      res.render('index', { title: '查询成功' })
    } else {
      console.log(err)
    }
  })
})

// 删除数据(删除符合条件的全部数据哦)
router.get('/testdeletemany', function (req, res) {
  global.db.__DeleteMany('student', { "age": { $gte: 19 } }, function (err, result) {
    if (!err) {
      console.log(result)
      res.render('index', { title: '删除成功' })
    } else {
      console.log(err)
    }
  })
})

// 修改数据(满足条件的数据全部都会被修改)

router.get('/testupdatemany', function (req, res) {
  global.db.__updateMany(
    'student',
    {
      "name": "zjj"
    },
    {
      $set: { name: "cnm" }
    },
    function (err, result) {
      if (!err) {
        console.log(result)
        res.render('index', {
          title: '修改成功'
        })
      }
    }
  )
})


// 统计总数
router.get('/count', function (req, res) {
  global.db.__getCount('student', {}, function (count) {
    console.log(count)
    res.render('index', {
      title: `一共${count}条数据`
    })
  })
})


// 分页显示
// page 是页数,从 0 开始
router.get('/testfingbypage', function (req, res) {
  global.db.__findByPage('student', {}, {
    "pageamount": 6,
    "page": 0
  }, function (err, result) {
    if (err) {
      throw err;
    }
    res.send(result);
    console.log(result.length);
  })
})

module.exports = router;

启动项目:

npm start



最近发表
标签列表