node常用模块

fs(文件系统) 模块

fs 模块提供了一个 API,用于以模仿标准 POSIX 函数的方式与文件系统进行交互。

所有文件系统操作都具有同步和异步的形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
读取文件;
const fs = require('fs');

// 异步读取
fs.readFile('./index.txt', 'utf8', (err, data) => {
console.log(data); // Hello Nodejs
});

// 同步读取
const data = fs.readFileSync('./index.txt', 'utf8');

console.log(data); // Hello Nodejs

// 创建读取流
const stream = fs.createReadStream('./index.txt', 'utf8');

// 这里fs.createReadStream用到了前面介绍的events eventEmitter.on() 方法来监听事件
stream.on('data', data => {
console.log(data); // Hello Nodejs
});

写入/修改文件
写入文件时,如果文件不存在,则会创建并写入,如果文件存在,会覆盖文件内容.

1
2
3
4
5
6
7
8
9
10
11
const fs = require('fs');
// 异步写入
fs.writeFile('./write.txt', 'Hello Nodejs', 'utf8', err => {
if (err) throw err;
});
// 同步写入
fs.writeFileSync('./writeSync.txt', 'Hello Nodejs');
// 文件流写入
const ws = fs.createWriteStream('./writeStream.txt', 'utf8');
ws.write('Hello Nodejs');
ws.end();

删除文件/文件夹
删除文件

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// 异步删除文件
fs.unlink('./delete.txt', err => {
if (err) throw err;
});

// 同步删除文件
fs.unlinkSync('./deleteSync.txt');
删除文件夹;
// 异步删除文件夹
fs.rmdir('./rmdir', err => {
if (err) throw err;
});

// 同步删除文件夹
fs.rmdirSync('./rmdirSync');
创建文件夹;
// 异步创建文件夹
fs.mkdir('./mkdir', err => {
if (err) throw err;
});

// 同步创建文件夹
fs.mkdirSync('./mkdirSync');
重命名文件 / 文件夹;
const fs = require('fs');

// 异步重命名文件
fs.rename('./rename.txt', './rename-r.txt', err => {
if (err) throw err;
});

// 同步重命名文件夹
fs.renameSync('./renameSync', './renameSync-r');
复制文件 / 文件夹;
const fs = require('fs');

// 异步复制文件
fs.copyFile('./copy.txt', './copy-c.txt', (err, copyFiles) => {
if (err) throw err;
});

// 同步复制文件夹
fs.copyFileSync('./null', 'null-c');
文件夹状态 - 文件 / 文件夹;
const fs = require('fs');

// 异步获取文件状态
fs.stat('./dir', (err, stats) => {
if (err) throw err;
// 是否是文件类型
console.log(stats.isFile()); // false
// 是否是文件夹类型
console.log(stats.isDirectory()); // true
});

// 同步获取文件状态
const stats = fs.statSync('./stats.txt');

// 是否是文件类型
console.log(stats.isFile()); // true
// 是否是文件夹类型
console.log(stats.isDirectory()); // false

events 模块

Node 是基于事件驱动的,其就是通过核心模块 Events 实现的。 Events 模块定义了 EventEmitter 类。实际上就是发布订阅模式。所有可能触发事件的对象都是继承自 EventEmitter 类的,其主要包含下面方法:

  • addEventListener
  • on
  • once
  • removeListener
  • removeAllListeners
  • setMaxListeners
  • emit

使用 EventEmitter
其他类需要触发事件等,都需要自行继承这个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
let util = require('util')
let EventEmitter = require('events')

function OtherClass(path) {
EventEmitter.call(this)
}
util.inherits(OtherClass, EventEmitter)
newListener 事件
EventEmitter 实例还可以监听一个 newListener 事件,即每次给这个实例添加新的监听函数时,都会触发 newListener 事件。

this.on('newListener', function (type, listener) {
// 每当监听一个事件时,就执行某些行为
})

stream 模块

流(stream)是 Node.js 中处理流式数据的抽象接口。 stream 模块用于构建实现了流接口的对象。

使用 stream 的场景:

使用 fs.readFile 读取文件时会将数据整个读取到内存中再处理,当处理大文件时,会极大的展示资源,这时就是使用 stream 的时候了。

Stream 不会一次性的读取文件,而是分批次的读取适量的内容到缓存区进行操作,这样对内存的占用会少很多。

流的四种基本类型

Writable - 可写入数据的流(例如 fs.createWriteStream())。

Readable - 可读取数据的流(例如 fs.createReadStream())。

Duplex - 可读又可写的流(例如 net.Socket)。

Transform - 在读写过程中可以修改或转换数据的 Duplex 流(例如 zlib.createDeflate())。

缓冲

缓冲区有大小限制,由 highWaterMark 指定字节总数(对象模式下指定对象总数)。调用 stream.push(chunk)时,数据缓冲在可读流中,等待被消费,如果缓冲区的数据大小达到了 highWaterMark 指定的阈值,流会停止读取数据,直到当前缓冲区的数据被消费。

用于消费的 api

使用继承自 events 的 emitter api 来通讯状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const file = fs.createReadStream('./test.txt', {
highWaterMark: 2,
flags: 'r',
encoding: 'utf8',
});

file.on('open', a => {
console.log('open', a);
});

file.on('data', chunk => {
console.log('data', chunk);
});

file.on('end', chunk => {
console.log('end', chunk);
});

file.on('close', a => {
console.log('close', a);
});
// open -> data -> data -> ... -> end -> close

(异步)事件触发顺序 open -> data -> data -> … -> end -> close

URL 模块

url 模块用于处理与解析 URL。

URL 字符串是结构化的字符串,包含多个含义不同的组成部分。 解析字符串后返回的 URL 对象,每个属性对应字符串的各个组成部分。

url 模块提供两种 api 来处理 url。(两种 api 的处理结果不同,详细)

const url = require(‘url’)
// WHATWG 标准
const myUrl = new url(‘https://baidu.com:8080/a/b/c?q=str#hash')
// 遗留 api
const myUrl2 = url.parse(‘https://baidu.com:8080/a/b/c?q=str#hash')
以下介绍的都是 WHATWG 标准解析出的对象

URL 对象的属性
const url = require(“url”);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const url = require("url");

const myURL = new url("https://github.com/webfansplz#hello");
console.log(myURL);
{
href: 'https://github.com/webfansplz#hello', // 序列化的 URL
origin: 'https://github.com', // 序列化的 URL 的 origin
protocol: 'https:', // URL 的协议
username: '', // URL 的用户名
password: '', // URL 的密码
host: 'github.com', // URL 的主机
hostname: 'github.com', // URL 的主机名
port: '', // URL 的端口
pathname: '/webfansplz', // URL 的路径
search: '', // URL 的序列化查询参数
searchParams: URLSearchParams {}, // URL 查询参数的 URLSearchParams 对象
hash: '#hello' // URL 的片段
}

URL 对象属性 除了 origin 和 searchParams 是只读的,其他都是可写的.

  1. 序列化 URL
1
2
3
4
5
6
7
8
9
const { URL } = require('url');

const myURL = new URL('https://github.com/webfansplz#hello');

console.log(myURL.href); // https://github.com/webfansplz#hello

console.log(myURL.toString()); // https://github.com/webfansplz#hello

console.log(myURL.toJSON()); // https://github.com/webfansplz#hello

初识MongoDB

数据库分类

关系型

SQL Server MySQL Access ORACLE

数据库 –> 表 –> 记录

非关系型

MongoDb 文档型的非关系数据库

安装

官网下载合适版本
不停的下一步,下一步
增加环境变量,以便直接在 shell 中使用
数据库 –> 集合 –> 文档 database –> collection –> document

存储格式 BSON 类似于 JSON

每一个 {}称为一条文档

{ ​ “name” : “小明”, ​ “age” : 18, ​ “hobby”: [“睡觉”, “吃饭”] }

命令操作

创建数据库

mongod:
mongod --dbpath dir # 打开或新建一个数据库 # mongod --dbpath E:\mongodb\mydb
mongo:
use dbname # 新建叫做 dbname 的数据库, 同时进入 dbname
初步操作

1
2
3
4
5
6
7
show dbs # 查看所有的数据库
show collections # 查看当前库下所有的 集合

## 在叫做 collectionName 的集合中插入一条文档,如果集合不存在,则新建该集合
db.collectionName.insert(obj)
## 查找名为 collectionName 集合的所有文档
db.collectionName.find()

导入数据

假设 C:\user\db\test.json 是 1000 条文档

1
2
3
4
5
6
7
8
mongoimport --db test --collection user --drop --file C:\user\db\test.json

## 以上操作会把 test.json 里的文档全部导入到 数据库 test -> 集合 user 中

--db 导入到哪个库
--collection 导入到哪个集合
--drop 清空集合中原有文档
--file 要导入的文件路径

CRUD

假设集合名叫 user

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
## 查询所有文档
db.user.find()

# 查询 k 的值为 v 的所有文档
db.user.find({k: v})

# and 操作
# 查询 k1 的值为 v1 且 k2 的值为 v2 的所有文档
db.user.find({k1: v1, k2: v2})

# or 操作
# 查询 k1 的值为 v1 或 k2 的值为 v2 的所有文档
db.user.find({$or: [{k1: v1}, {k2: v2}]})

# 比较(大于,小于)
db.user.find({k: {$gt: v}}) # 查询 k 的值大于 v 的文档
db.user.find({k: {$lt: v}}) # 查询 k 的值小于 v 的文档
# $gt 大于
# $lt 小于

# 组合
db.user.find({k: {$gt: v1, $lt: v2}}) # 查询 k 的值大于 v1 同时小于 v2 的文档
# 更新
db.user.update(
{k: v1}, # 查询条件
{
$set: {k: v2} # 把查到的 k 改为 v2
}
)
# 更新详细语法
db.user.update(
<query>, # 查询条件
<update>, # 更新方式,如 $set, $inc 等
{
multi: <boolean>, # (可选)默认为 false,只匹配找到的第一条, 如果为 true, 所有满足条件的都匹配
}
)
# 删除
db.dropDatabase() # 删除当前所在数据库
db.user.drop() # 删除名为 user 的集合
db.user.remove({k: v}) # 删除匹配到的所有 k 值为 v 的文档
db.user.remove({k: v}, {justOne: true}) # 删除第一个匹配到的所有 k 值为 v 的文档
db.user.remove({}) # 清空 user 集合
排序
db.user.find({查询条件}).sort({k1: 1}, {k2: -1})

# 按照 k1 来排序, 如果 k1 的值相同,按照 k2 来排序

# 1 升序, -1 降序

node 里简单封装增删改查

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// node mongodb 版本 v3.1.13 适用
const MongoClient = require('mongodb').MongoClient;
const log = console.log.bind(console);

class Dao {
/**
* 构造函数
* @param {string} url
* @param {string} dbname
* @param {string} colname
*/
constructor(url, dbname, colname) {
this.url = url;
this.dbname = dbname;
this.colname = colname;
}

/**
* 连接数据库
*/
_connect() {
return new Promise((resolve, reject) => {
MongoClient.connect(this.url, { useNewUrlParser: true }, (err, client) => {
if (err) {
reject(err);
} else {
resolve(client);
}
});
});
}

/**
* 插入文档
* @param {arr || object} documents
* @param {boolean} insertMany
* 使用 insertMany(arr), 在 arr === [] 时,会报错
*/
insert(documents, insertMany = false) {
return new Promise((resolve, reject) => {
this._connect()
.then(client => {
let col = client.db(this.dbname).collection(this.colname);
if (insertMany) {
col
.insertMany(documents)
.then(res => {
resolve(res);
})
.catch(err => {
log(err);
});
client.close();
} else {
col
.insertOne(documents)
.then(res => {
resolve(res);
})
.catch(err => {
log(err);
});
client.close();
}
})
.catch(err => {
reject(err);
});
});
}

/**
* 查询
* @param {object} document
*/
query(document, pageConfig) {
document = document || {};
pageConfig = pageConfig || {};
let page = pageConfig.page;
let amount = pageConfig.amount;
const resData = [];

return new Promise((resolve, reject) => {
this._connect()
.then(client => {
let col = client.db(this.dbname).collection(this.colname);
let cursor = col
.find(document)
.limit(amount)
.skip((page - 1) * amount);
cursor.each((err, data) => {
if (err) {
reject(err);
client.close();
} else if (data !== null) {
resData.push(data);
} else {
resolve(resData);
client.close();
}
});
})
.catch(err => {
log(err);
});
});
}

/**
* 删除集合中的数据
* @param {object} query
* @param {boolean} deleteMany
*/
delete(query, deleteMany = false) {
return new Promise((resolve, reject) => {
this._connect()
.then(client => {
let col = client.db(this.dbname).collection(this.colname);
if (deleteMany) {
col.deleteMany(query).then(res => {
resolve(res);
client.close();
});
} else {
col.deleteOne(query).then(res => {
resolve(res);
client.close();
});
}
})
.catch(err => {
log(err);
});
});
}

/**
* 更新
* @param {obj} filter
* @param {obj} updater
*/
update(filter, updater) {
let uptaterCpy = { $set: updater };

return new Promise((resolve, reject) => {
this._connect()
.then(client => {
let col = client.db(this.dbname).collection(this.colname);
col.updateMany(filter, uptaterCpy).then(res => {
resolve(res);
client.close();
});
})
.catch(err => {
log(err);
});
});
}
}

//
let url = 'mongodb://localhost:27017';
let dbname = 'test';
let colname = 'user';
let dao = new Dao(url, dbname, colname);

let arr = [];
for (let i = 0; i < 20; i++) {
arr.push({
userid: '234',
age: i,
});
}