Fork me on GitHub

node-mongodb上手指南

目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1. MongoDB介绍
2. MongoDB本地安装
3. MongoDB本地操作
3.1 库操作
3.2 表操作
4. node-mongodb安装
5. node-mongodb连接
6. node-mongodb语法和执行
- 插入
- 查询
- 修改
- 删除
- 存储过程
7. node-mongoose介绍和使用
7.1 mongoose名词介绍
7.3 node-mongoose安装
7.4 node-mongoose语法和执行
7.4.1 Schema,Modal创建
- 索引和默认值
- 验证器
7.4.2 数据库操作
- 插入
- 删除
- 修改
- 修改器和更新器
- 查询
- 条件查询
- 数量查询
- 根据id查询
- 分页查询
- aggregate
8. 其他

1.mongodb介绍

  开源,高性能的NoSQL数据库;支持索引、集群、复制和故障转移、各种语言的驱动程序;高伸缩性;

2. mongodb本地安装

官方安装说明: http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/

安装成功后启动:
我本地是:mongod –dbpath “f:\data\db”

MongoDB默认端口是27017;

3. mongodb本地操作

成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作

a. 库操作

新建数据库:第一步:use 新建数据库名;第二步:进行此库相关的操作;如果不进行第二步,该数据库不会被创建

  • 查看数据库:show dbs;
  • 新建表:db.createCollection(‘要新建的表名’);
  • 查看当前数据库下表: show collections;
  • 删除当前数据库指定表:db.表名.drop();
  • 删除当前数据库:db.dropDatabase();

提示:

  1. 默认为存在“admin”和“local”两个数据库;admin数据库是存放管理员信息的数据库,认证会用到;local是存放replication相关的数据;这两处本篇都没有涉及到;
  2. find();是个查询操作,后面会讲到,上面用到主要是为了演示use不存在的库后,进行相关操作会创建出这个库;
  3. MongoDB没有像MySQL或MSSQL等数据库这么严格的规定,不是非得要先建库、建表、建各种字段,以后的操作中慢慢的会体会到^_^!

b. 表操作

1. 插入
方法一:db.表名.insert(数据);  

  1. 没有去创建新表,其实通过插入操作也会自动创建
  2. _id,是mongodb自已生成的,每行数据都会存在,默认是ObjectId,可以在插入数据时插入这个键的值(支持mongodb支持的所有数据类型)

方法二:db.表名.save(数据);

  1. save也可达到insert一样的插入效果
  2. _id可以自已插入
  3. 一个表中不一定要字段都相同

那它们有什么区别?  
  虽然insert和save方法都可以插入数据,当默认的“_id”值已存在时,调用insert方法插入会报错;而save方法不会,会更新相同的_id所在行数据的信息

2. 查询

  • 查询表中所有数据:db.表名.find();
  • 按条件查询(支持多条件):db.表名.find(条件);
  • 查询第一条(支持条件):db.表名.findOne(条件);
  • 限制数量:db.表名.find().limit(数量);
  • 跳过指定数量:db.表名.find().skip(数量);

查询不止这些,还有些高级查询,自行去了解一下^_^!

3. 修改

  • 前面save在_id字段已存在是就是修改操作,按指定条件修改语法如下:
  • db.表名.update({“条件字段名”:”字段值”},{$set:{“要修改的字段名”:”修改后的字段值”}});

4. 删除

  • db.表名.remove(条件);

5. 存储过程

1
2
3
4
5
6
7
8
  // 创建存储过程:
db.system.js.save({_id:"存储过程ID",
value:function(参数){
-- 逻辑主体;
return 返回;
}});
// 调用存储过程
db.eval("存储过程ID()");

所有存储过程都存放在db.system.js中

4. node-mongodb安装

  • npm install mongodb

5. node-mongodb连接

  1. 创建连接对象,需要传入连接数据库的一些连接参数
1
2
3
4
5
6
7
8
9
10
11
12
const mongodbClient = require('mongodb').MongoClient;
const url = 'mongodb://locolhost:27017';
const dbName = 'test'; // 数据库名称

mongodbClient.connect(url, function(err, client){
console.log('连接成功!');
const db = client.db(dbName);
const collection = db.collection('test'); // 连接到表
// 执行mongo语句
......
client.close(); // 关闭连接
})
  1. 关闭连接

关闭一个连接使用close();

6. node-mongodb语法和执行

a. 插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  const insertData = function(collection, callback) {   
//插入数据
const data = [{"name":'zhangsan',"age":21},{"name":'lisi',"age":22}];
collection.insert(data, function(err, result) {
if(err){
console.log('Error:'+ err);
return;
}
callback(result);
});
}
mongodbClient.connect(url, function(err, client){
console.log('连接成功!');
const db = client.db(dbName);
const collection = db.collection('test');
insertData(collection, function(result){
console.log(result);
});
})

b. 查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  const selectData = function(collection, callback) {  
// 查询所有
let whereStr = {"name":"张三"};
collection.find(whereStr).toArray(function(err, result) {
if(err){
console.log('Error:'+ err);
return;
}
callback(result);
});
// 条件查询 查询参数很多,自行查阅
collection.find({"age":{$gt:30}}).toArray(function(err, result) {
if(err)
{
console.log('Error:'+ err);
return;
}
callback(result);
});
}
......

c. 修改

1
2
3
4
5
6
7
8
9
10
11
  const updateData = function(collection, callback) {  
const whereStr = {"name":'zhangsan'};
const updateStr = {$set: { "age" : 100 }};
collection.update(whereStr, updateStr, function(err, result) {
if(err){
console.log('Error:'+ err);
return;
}
callback(result);
});
}

d: 删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  var delData = function(db, callback) {  
//连接到表
var collection = db.collection('tb2');
//删除数据
var whereStr = {"name":'wilson001'};
collection.remove(whereStr, function(err, result) {
if(err)
{
console.log('Error:'+ err);
return;
}
callback(result);
});
}

e: 存储过程

1
2
3
4
5
6
7
8
9
10
  const invokeProcData = function(db, callback) {  
db.eval('get_tb2_count()', function(err, result) {
if(err)
{
console.log('Error:'+ err);
return;
}
callback(result);
});
}

7. mongoose介绍和使用

一般我们不直接用MongoDB的函数来操作MongoDB数据库,针对它的进行再次封装的东西很多,且更利于编程实现,比如:mongoose、mongoskin、mongolian等等,应用性不错;
Mongoose就是一套操作MongoDB数据库的接口,且应用较多。

1. 名词解释

  • Schema: 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力

    • Schema.Type:是由Mongoose内定的一些数据类型,基本数据类型都在其中,他也内置了一些Mongoose特有的Schema.Type。当然,你也可以自定义Schema.Type,只有满足Schema.Type的类型才能定义在Schema内。NodeJS中的基本数据类型都属于Schema.Type,另外Mongoose还定义了自己的类型

      // 从官网截取过来的,举例:
      var ExampleSchema = new Schema({
          name:String,
          binary:Buffer,
          living:Boolean,
          updated:Date,
          age:Number,
          mixed:Schema.Types.Mixed, //该混合类型等同于nested
          _id:Schema.Types.ObjectId,  //主键
          _fk:Schema.Types.ObjectId,  //外键
          array:[],
          arrOfString:[String],
          arrOfNumber:[Number],
          arrOfDate:[Date],
          arrOfBuffer:[Buffer],
          arrOfBoolean:[Boolean],
          arrOfMixed:[Schema.Types.Mixed],
          arrOfObjectId:[Schema.Types.ObjectId]
          nested:{
              stuff:String,
          }
      });
      
  • Model: 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
  • Entity: 由Model创建的实体,他的操作也会影响数据库

Schema生成Model,Model创造Entity,Model和Entity都可对数据库操作造成影响,但Model比Entity更具操作性

2. node-mongoose安装

npm install mongoose

3. 连接mongoose

创建一个文件db.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const mongoose = require('mongoose'),
DB_URL = 'mongodb://localhost:27017/test';
// 若有密码,则url:mongodb://username:password@host:port/database?options...'
// 连接
mongoose.connect(DB_URL);

// 连接成功
mongoose.connection.on('connected', function () {
console.log('Mongoose connection open to ' + DB_URL);
});

// 连接异常
mongoose.connection.on('error',function (err) {
console.log('Mongoose connection error: ' + err);
});

// 连接断开
mongoose.connection.on('disconnected', function () {
console.log('Mongoose connection disconnected');
});

module.exports = mongoose;

4. mongoose使用

举例,创建了一个用户登录信息表,对此数据进行增删改查

  1. 创建文件user.js, 创建Schema,Model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const mongoose = require('./db.js'),
Schema = mongoose.Schema;

const UserSchema = new Schema({
username : { type: String, index: true }, //用户账号
userpwd: { type: String, required: true }, //密码
userage: {type: Number, min: 18, max 80 }, //年龄
logindate : { type: Date, default: new Date()}, //最近登录时间
city:{ type:'String', enum:['北京','上海'] }, // 城市
other:{
type:'String',
validate:[validator,err] //validator是一个验证函数,err是验证失败的错误信息
}
});
module.exports = mongoose.model('User',UserSchema);

上面有提到几个定义

  • 索引和默认值,即 index和default
  • 验证器,即
    • required 非空验证
    • min/max 范围验证(边值验证)
    • enum/match 枚举验证/匹配验证
    • validate 自定义验证规则
  1. 进行数据库操作
  • a. 插入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    const User = require("./user.js");
function insert() {
const user = new User({
username : 'zhangsan',
userpwd: 'abcd',
userage: 37,
logindate : new Date()
});

user.save(function (err, res) {
if (err) {
console.log("Error:" + err);
}
else {
console.log("Res:" + res);
}
});
}
insert();
  • b. 修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const User = require("./user.js");
function update(){
const wherestr = {'username' : 'zhangsan McGrady'};
const updatestr = {'userpwd': 'zzzz'};

User.update(wherestr, updatestr, function(err, res){
if (err) {
console.log("Error:" + err);
}
else {
console.log("Res:" + res);
}
})
}
update();

修改器和更新器:
为了更快进行更新的操作。在update中需要写很多选择器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$inc增减修改器,只对数字有效.下面的实例: 找到 age=22的文档,修改文档的age值自增1
Model.update({‘age’:22}, {‘$inc’:{‘age’:1} } );
执行后: age=23

$set指定一个键的值,这个键不存在就创建它.可以是任何MondoDB支持的类型
Model.update({‘age’:22}, {‘$set’:{‘age’:’haha’} } );
执行后: age=’haha’

$unset同上取反,删除一个键
Model.update({‘age’:22}, {‘$unset’:{‘age’:’haha’} } );
执行后: age键不存在

$push给一个键push一个数组成员,键不存在会创建
Model.update({‘age’:22}, {‘$push’:{‘array’:10} } );
执行后: 增加一个 array 键,类型为数组, 有一个成员 10

$addToSet向数组中添加一个元素,如果存在就不添加
Model.update({‘age’:22}, {‘$addToSet’:{‘array’:10} } );
执行后: array中有10所以不会添加

$each遍历数组, 和 $push 修改器配合可以插入多个值
Model.update({‘age’:22}, {‘$push’:{‘array’:{‘$each’: [1,2,3,4,5]}} } );
执行后: array : [10,1,2,3,4,5]

$pop向数组中尾部删除一个元素
Model.update({‘age’:22}, {‘$pop’:{‘array’:1} } );
执行后: array : [10,1,2,3,4] tips: 将1改成-1可以删除数组首部元素

$pull向数组中删除指定元素
Model.update({‘age’:22}, {‘$pull’:{‘array’:10} } );
执行后: array : [1,2,3,4] 匹配到array中的10后将其删除
  • c. 删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    const User = require("./user.js");
function del(){
const wherestr = {'username' : 'zhangsan'};

User.remove(wherestr, function(err, res){
if (err) {
console.log("Error:" + err);
}
else {
console.log("Res:" + res);
}
})
}
del();

另外,删除和更新的其他方法,常用方法有:

  • Model.findByIdAndUpdate(id, [update], [options], [callback]) // 找到指定id记录并更新
  • Model.findOneAndUpdate([conditions], [update], [options], [callback]) // 找到一条记录并更新
    * Model.findByIdAndRemove(id, [options], [callback]) // 找到指定id记录并删除
  • Model.findOneAndRemove(conditions, [options], [callback]) // 找到一条记录并删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const User = require("./user.js");
function findByIdAndUpdate(){
const id = '56f2558b2dd74855a345edb2';
cibst updatestr = {'userpwd': 'abcd'};
User.findByIdAndUpdate(id, updatestr, function(err, res){
if (err) {
console.log("Error:" + err);
}
else {
console.log("Res:" + res);
}
})
}
findByIdAndUpdate();
  • d. 查询

查询有直接查询和链式查询,链式查询只有在执行exec方法时才执行查询,而且必须有回调

  • 条件查询
    Model.find(conditions, [fields], [options], [callback])
    //fields和options是可选参数, field的值中,1为包括,0为不包括,options: 选项参数
    //fields: 参数用于字段映射,默认情况下,MongoDB会返回匹配文档的所有字段,使用映射(projection)设置希望返回的字段,用于取文档字段的子集,相当于SQL中SELECT后面我们需要的字段

    • User.find({‘username’ : ‘zhangsn’}, {“username”: 1 ,”_id”: 0}, callback); // 输出只会有username字段,设置方法如上,1表示查询输出该字段,0表示不输出
    • User.find({userage: {$gte: 21, $lte: 65}}, callback); // 这表示查询年龄大于等21而且小于等于65岁

      参数还有:

           $or    或关系
           $nor    或关系取反
          $gt    大于
          $gte    大于等于
          $lt     小于
          $lte     小于等于
          $ne            不等于
          $in             在多个值范围内
          $nin           不在多个值范围内
          $all            匹配数组中多个值
          $regex  正则,用于模糊查询
          $size   匹配数组大小
          $maxDistance  范围查询,距离(基于LBS)
          $mod     取模运算
          $near   邻域查询,查询附近的位置(基于LBS)
          $exists    字段是否存在
          $elemMatch  匹配内数组内的元素
          $within  范围查询(基于LBS)
          $box    范围查询,矩形范围(基于LBS)
          $center       范围醒询,圆形范围(基于LBS)
          $centerSphere  范围查询,球形范围(基于LBS)
          $slice    查询字段集合中的元素(比如从第几个之后,第N到第M个元素
      
    • User.find({‘username’:{$regex:/m/i}}, [callback]) // 模糊查询,正则匹配有’m’的名字,且不区分大小写
  • 数量查询
    Model.count(conditions, [callback]) // res结果会输出数量,也可以传入条件做条件查询。

  • 根据id查询
    Model.findById(id, [fields], [options], [callback]) // 要据ID得到数据

  • 分页查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const User = require("./user.js");
function getByPager(){
const pageSize = 5; //一页多少条
const currentPage = 1; //当前第几页
const sort = {'logindate':-1}; //排序(按登录时间倒序)
const condition = {}; //条件
const skipnum = (currentPage - 1) * pageSize; //跳过数

User.find(condition).skip(skipnum).limit(pageSize).sort(sort).exec(function (err, res) {
if (err) {
console.log("Error:" + err);
}
else {
console.log("Res:" + res);
}
})
}
getByPager();
  • e. aggregate
    在MongoDB中,聚合(aggregate)主要用于进行处理数据,比如统计求和,求平均数等,并返回计算后的数据结果,这给我们带来了很多便捷之处,因为可以在读取数据的同时进行数据处理
    例如:
1
2
3
4
5
// $match用于获取年龄大于20小于或等于40记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。
User.aggregate([
{ $match : { userage : { $gt : 20, $lte : 40 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
]);

下面列举一些:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

更多参数可以参考下方参考链接。

8. 其他

注意:

  • 表”应该描述为“collection(集合)”;“行”应该描述为“文档(document)”,一个database中可以有多个collection,一个collection中又可以有多个document
  • 用CMD中使用mongo.exe操作时,插入中文遇一了问题,原因是MongoDB默认编辑是utf-8,而CMD是GBK,所以在CMD窗口中执行这个命令修改编辑即可:chcp 65001
  • 注意mongodb严格区分大小写,比如查询 db.tb2.find({“name”:”wilson0”})和 db.tb2.find({“Name”:”wilson0”}) 并不是用的同一字段做的条件;

参考:
mongodb: https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/
mongodb查询参数: https://mongodb-documentation.readthedocs.io/en/latest/reference/operator/gt.html
mongoose: http://mongoosejs.com/docs/api.html#Aggregate
blog:
http://www.cnblogs.com/zhongweiv/p/node_mongodb.html
https://cnodejs.org/topic/504b4924e2b84515770103dd

-------------本文结束感谢您的阅读-------------