mongo命令行

mongo Shell:每个数据库都有自己独特的命令,MSSQL和mySql用的都是Sql命令,MongoDB的操作命令就是前端最熟悉的JS命令。下面来看几个例子:

// 定义一个变量
> var a = 'hello'
> print(a)
hello
1
2
3
4

需要注意:这里打印需要使用print,而不是console

// 定义一个函数
> function test(){
... return '123';
... }
> print(test())
123
1
2
3
4
5
6

基本Shell命令

  • show dbs:显示已有数据库,刚安装好的情况下,默认会有local、admin(config),这是MongoDB的默认数据库,我们在新建库时是不允许起这些名称的,需要注意的是:该命令不显示数据为空的数据库;
  • use admin:进入admin数据,也可以理解为使用数据库。成功会显示:switched to db admin;
  • show collections:显示数据库中的集合;
  • db:显示当前我们使用的数据库名称,这个命令最常用,因为我们在做任何操作之前都应该先查看一下当前所在的数据库,以免造成操作错误。

MongoDB存储结构

由上图可以看出:关系型数据库的数据结构最顶层是数据库,数据库库下面是数据表,数据表下面是数据。但是MongoDB有所不同,数据库下面是集合,集合下面是文件。其实为了方便记忆,我们可以简单理解数据表就是集合,数据行就是文件。

数据基本操作

  • use db:进入对应的数据库,需要注意:use不仅可以进入一个数据库,如果对应的数据库不存在,会自动创建响应的数据库,但是在没有集合前,该数据库默认为空;
  • db.集合.insert():新建集合和插入数据,当集合不存在时,会自动新建一个集合,并向里边插入对应数据;
  • db.集合.find():查询集合里的所有文件数据,这条命令会列出集合下的所有数据,可以看到MongoDB是自动给我们加入了索引值的;
  • db.集合.findOne():查询集合中的第一个文件数据,需要注意:MongoDB中的所有组合单词都使用首字母小写的驼峰式写法;
  • db.集合.update({查询},{修改}):修改文件数据,第一个是查询条件,第二个是要修改成的值。需要注意的是:可以新增文件数据项的;
  • db.集合.remove(条件):删除文件数据,注意的是要跟一个条件;
  • db.集合.drop():删除整个集合,这个在实际工作中一定要谨慎使用,如果是程序,一定要二次确认;
  • db.dropDatabase():删除整个数据库,在删除库时,一定要先进入数据库,然后再删除。实际工作中这个基本不用,实际工作肯定需要保留数据和痕迹的。
// 进入user数据库
> use user
switched to db user

// 查看数据库中所有集合
> show collections
books
people
users

// 向classRoom集合中插入两条数据
> db.classRoom.insert({"name": "lisi"})
WriteResult({ "nInserted" : 1 })
> db.classRoom.insert({"name": "wangwu"})
WriteResult({ "nInserted" : 1 })

// 重新查看数据库中的所有集合
> show collections
books
classRoom
people
users

// 查询所有数据
> db.classRoom.find()
{ "_id" : ObjectId("5cba9a0b057780bbe7ea1514"), "name" : "lisi" }
{ "_id" : ObjectId("5cba9a13057780bbe7ea1515"), "name" : "wangwu" }

// 查询第一个文件数据
> db.classRoom.findOne()
{ "_id" : ObjectId("5cba9a0b057780bbe7ea1514"), "name" : "lisi" }

// 给name为lisi的数据项增加age
> db.classRoom.update({"name": "lisi"}, {"name": "lisi", age: 18})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

// 重新查询
> db.classRoom.find()
{ "_id" : ObjectId("5cba9a0b057780bbe7ea1514"), "name" : "lisi", "age" : 18 }
{ "_id" : ObjectId("5cba9a13057780bbe7ea1515"), "name" : "wangwu" }

// 删除数据
> db.classRoom.remove({"name": "wangwu"})
WriteResult({ "nRemoved" : 1 })
// 重新查询
> db.classRoom.find()
{ "_id" : ObjectId("5cba9a0b057780bbe7ea1514"), "name" : "lisi", "age" : 18 }

// 删除整个集合
> db.classRoom.drop()
true
// 重新查看数据库所有集合
> show collections
books
people
users

// 新建user2数据库
> use user2
switched to db user2
// 删除user2数据库
> db.dropDatabase()
{ "dropped" : "user2", "ok" : 1 }
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

插入数据

// 切换数据库(数据库不存在也没关系)
// 如果test数据库不存在则创建,存在则切换到test数据库
> use test
switched to db test
1
2
3
4
// 向test_collection集合中插入数据
> db.test_collection.insert({name: '鲁班七号'})
WriteResult({ "nInserted" : 1 })
1
2
3

查询数据

// 查看存在的数据库
> show dbs
admin    0.000GB
config   0.000GB
local    0.000GB
myDbs    0.000GB
myheros  0.000GB
test     0.000GB
1
2
3
4
5
6
7
8
// find有6个参数
> db.books.find(query, fields, limit, skip, batchSize, options)
1
2
// 查看数据库版本
> db.version()
3.6.3
1
2
3
// 使用find查找数据
// find方法参数为空则返回全部数据
> db.test_collection.find()
{ "_id" : ObjectId("5b8a56d52c0516ea271c4f82"), "name" : "鲁班七号" }
{ "_id" : ObjectId("5b8a96fc2c0516ea271c4f83"), "name" : "后羿" }
// 返回指定name的数据
> db.test_collection.find({name: '后羿'})
{ "_id" : ObjectId("5b8a96fc2c0516ea271c4f83"), "name" : "后羿" }
1
2
3
4
5
6
7
8
// for循环插入多条数据
> for(i=2;i<100;i++)db.test_collection.insert({x:i})
WriteResult({ "nInserted" : 1 })
1
2
3
// 查看集合中数据条数
> db.test_collection.find().count()
100
1
2
3
// skip(n) 跳过n条数据
// limit(m) 限制返回m条数据
// sort({x:1}) 根据x字段排序,1表示升序,-1表示降序
> db.test_collection.find().skip(3).limit(4).sort({x:1})
{ "_id" : ObjectId("5b8a982c2c0516ea271c4f85"), "x" : 3 }
{ "_id" : ObjectId("5b8a982c2c0516ea271c4f86"), "x" : 4 }
{ "_id" : ObjectId("5b8a982c2c0516ea271c4f87"), "x" : 5 }
{ "_id" : ObjectId("5b8a982c2c0516ea271c4f88"), "x" : 6 }

> db.test.find().skip(3).limit(5).sort({x:-1})
{ "_id" : ObjectId("5cbaa480057780bbe7ea1577"), "x" : 97 }
{ "_id" : ObjectId("5cbaa480057780bbe7ea1576"), "x" : 96 }
{ "_id" : ObjectId("5cbaa480057780bbe7ea1575"), "x" : 95 }
{ "_id" : ObjectId("5cbaa480057780bbe7ea1574"), "x" : 94 }
{ "_id" : ObjectId("5cbaa480057780bbe7ea1573"), "x" : 93 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

更新数据

// 查询x:3数据
> db.test_collection.find({x:3})
{ "_id" : ObjectId("5b8a982c2c0516ea271c4f85"), "x" : 3 }
// 更新x:3数据为x:333
> db.test_collection.update({x:3}, {x:333})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
1
2
3
4
5
6
> db.test_collection.insert({x:100, y:100, z:100})
WriteResult({ "nInserted" : 1 })
// 部分数据更新采用$set
> db.test_collection.update({z:100},{$set:{y:99}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 查询更新后的结果
> db.test_collection.find({z:100})
{ "_id" : ObjectId("5b8a9be92c0516ea271c4fe6"), "x" : 100, "y" : 99, "z" : 100 }
1
2
3
4
5
6
7
8
// 第三个参数true,表示当y=100的数据不存在时,自动插入y=999的数据(即要更新的数据)
> db.test_collection.update({y:100},{y:999},true)
WriteResult({
	"nMatched" : 0,
	"nUpserted" : 1,
	"nModified" : 0,
	"_id" : ObjectId("5b8b4e4cc06181d9a6bb896b")
})
> db.test_collection.find({y:999})
{ "_id" : ObjectId("5b8b4e4cc06181d9a6bb896b"), "y" : 999 }
1
2
3
4
5
6
7
8
9
10
db.collection.update(<query>, <update>, {upsert: <boolean>,multi: <boolean>,writeConcern: <document> } )
1

参数说明:

  • query:update的查询条件;
  • update:update的对象和一些更新的操作符(如$,$inc...)等;
  • upsert:可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false;
  • multi:可选,mongodb 默认是false,只更新找到的第一条记录;
  • writeConcern:可选,抛出异常的级别。

删除数据

// 删除数据使用remove()方法,该方法必须传入参数,否则报错
> db.test_collection.remove()
2018-09-02T10:51:51.996+0800 E QUERY    [thread1] Error: remove needs a query :
DBCollection.prototype._parseRemove@src/mongo/shell/collection.js:357:1
DBCollection.prototype.remove@src/mongo/shell/collection.js:382:18
@(shell):1:1
// 删除y=999的数据
> db.test_collection.remove({y:999})
WriteResult({ "nRemoved" : 1 })
// 删除数据表
// 语法:db.表名.drop()
> db.test_collection.drop()
true
1
2
3
4
5
6
7
8
9
10
11
12
13

使用js文件写mongo命令

在命令行中写mongo的命令很麻烦,我们可以是用js文件的形式来写shell命令和执行。

const userName = 'liujie';
const timeStamp = Date.parse(new Date()); // 声明登录时的时间戳
const jsonData = {"loginUser": userName, "loginTime": timeStamp};
var db = connect('user'); // 连接数据库
db.login.insert(jsonData); // 插入数据

print('user print success'); // 成功则打印信息
1
2
3
4
5
6
7

执行写好的js文件:

➜  mongo demo1.js
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
user print success
1
2
3
4
5
6
7
> db.login.find()
{ "_id" : ObjectId("5cbaac8ff58ebe9136a70a0f"), "loginUser" : "liujie", "loginTime" : 1555737743000 }
>
1
2
3

批量插入数据

批量数据插入是以数组的方式进行的。

db.test.insert([
    {"name": "lisi"},
    {"name": "wangwu"}
])
1
2
3
4

在老版本MongoDB(3.2以前的版本基本都需要)是需要在Insert前加一个batch单词的,如下代码:

db.test.batchInsert([
    {"name": "lisi"},
    {"name": "wangwu"}
])
1
2
3
4

循环插入

新建js文件demo2.js,具体内容如下:

/**
 * 循环插入多条数据
 */
const startTime = (new Date()).getTime(); // 获取开始时间
var db = connect('user'); // 连接数据库
// 循环插入数据
for(let i = 0; i < 1000; i++) {
    db.test.insert({x: i});
}
const runTime = (new Date()).getTime() - startTime; // 计算时间差
print('demo run: ' + runTime + 'ms');
1
2
3
4
5
6
7
8
9
10
11
➜  mongo demo2.js
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
demo run:288ms
1
2
3
4
5
6
7

循环插入需要200多毫秒。

批量插入

新建js文件demo3.js,具体内容如下:

/**
 * 批量插入数据
 */
const startTime = (new Date()).getTime(); // 获取开始时间
var db = connect('user'); // 连接数据库
// 批量插入数据
const temArr = [];
for(let i = 0; i < 1000; i++) {
    temArr.push({x: i});
}
db.test.insert(temArr); // 批量一次性插入
const runTime = (new Date()).getTime() - startTime; // 计算时间差
print('demo run: ' + runTime + 'ms');
1
2
3
4
5
6
7
8
9
10
11
12
13
➜  mongo demo3.js
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
demo run: 12ms
1
2
3
4
5
6
7

批量插入仅仅需要十几毫秒。

需要注意:一次插入不要超过48M,像.zip和大图片等资源尽量采用静态存储,MongoDB存储静态路径就好。

update常见错误

/**
 * 批量增加一些数据
 */
var student1 = {
    name: 'lisi',
    age: 10,
    sex: 1,
    hobby: {
        hobbyOne: '篮球',
        hobbyTwo: '足球',
        hobbyThree: '羽毛球'
    },
    createTime: new Date()
};
var student2 = {
    name: 'wangwu',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '游泳',
        hobbyTwo: '健身',
        hobbyThree: '乒乓球'
    },
    createTime: new Date()
};
var student3 = {
    name: 'xiaohong',
    age: 13,
    sex: 1,
    hobby: {
        hobbyOne: '瑜伽',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    createTime: new Date()
};
var db = connect('user');
var studentArr = [student1, student2, student3];
db.student.insert(studentArr);
print('The data was inserted successfully');
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
// 查看插入后的数据
> db.student.find()
{ "_id" : ObjectId("5cbabb24bfc8fb0139b04d6a"), "name" : "lisi", "age" : 10, "sex" : 1, "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "足球", "hobbyThree" : "羽毛球" }, "createTime" : ISODate("2019-04-20T06:24:36.707Z") }
{ "_id" : ObjectId("5cbabb24bfc8fb0139b04d6b"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:24:36.707Z") }
{ "_id" : ObjectId("5cbabb24bfc8fb0139b04d6c"), "name" : "xiaohong", "age" : 13, "sex" : 1, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:24:36.707Z") }

// 修改小红的性别,这种写法是错误
> db.student.update({name: "xiaohong"}, {sex: 0})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 修改后再次查看所有数据,发现并不符合预期
> db.student.find()
{ "_id" : ObjectId("5cbabb24bfc8fb0139b04d6a"), "name" : "lisi", "age" : 10, "sex" : 1, "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "足球", "hobbyThree" : "羽毛球" }, "createTime" : ISODate("2019-04-20T06:24:36.707Z") }
{ "_id" : ObjectId("5cbabb24bfc8fb0139b04d6b"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:24:36.707Z") }
{ "_id" : ObjectId("5cbabb24bfc8fb0139b04d6c"), "sex" : 0 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

这样写的问题在于:我们的最后一条数据变成了只有sex:0,其它数据项全部丢失了。

正确写法:

/**
 * 修改单条数据的正确写法
 */

var db = connect('user');
var student3 = {
    name: 'xiaohong',
    age: 13,
    sex: 0,
    hobby: {
        hobbyOne: '瑜伽',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    createTime: new Date()
};

db.student.update({name: "xiaohong"}, student3);
print('The data was updated successfully');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

这时候我们需要删除student集合中的数据,因为xiaohong这个用户已经不在数据库中了,然后重新使用load方法载入插入数据再进行修改。

//执行命令如下:
db.student.drop()
load('./demo4.js')
load('./demo5.js')
1
2
3
4

现在这种方法才是正确的,数据修改正常了,但是我们会发现写起来非常麻烦,而且特别容易写错。接下来我们学习一下update修改器,可以很好的解决这个问题。

update修改器

$set修改器

$set修改器用来修改一个指定的键值(key)。

// 修改
> db.student.update({"name": "lisi"}, {"$set":{sex: 0, age: 20}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 查看修改后的数据
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "足球", "hobbyThree" : "羽毛球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 13, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z") }
1
2
3
4
5
6
7
8

修改嵌套内容

比如现在的lisi的爱好发生了变化,说她不会打篮球而是跳绳很好,需要进行修改。这时候我们会发现hobby数据是内嵌的,这时候我们可以属性的形式进行修改hobby.hobbyOne,代码如下:

// 修改
> db.student.update({"name": "lisi"}, {"$set": {"hobby.hobbyOne": "跳绳"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 查看
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyOne" : "跳绳", "hobbyTwo" : "足球", "hobbyThree" : "羽毛球"}, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 13, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z") }
1
2
3
4
5
6
7
8

$unset修改器

$unset的作用是:删除一个key值和键。当我们删除后,想加回来可以直接用$set进行添加。

// 删除hobby.hobbyOne
> db.student.update({"name":"lisi"},{$unset:{"hobby.hobbyOne":""}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 查询
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 13, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z") }
// 重新添加
> db.student.update({"name":"lisi"},{$set:{"hobby.hobbyOne":"篮球"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 13, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z") }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

$inc修改器

$inc修改器用于对数字进行计算,可以对value值进行修改,但是修改的必须是数字,字符串是不起作用的。现在把xiaohong的年龄减去3岁,就可以直接用$inc来操作。

> db.student.update({"name":"xiaohong"},{$inc: {"age": -3}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z") }
1
2
3
4
5
6

multi选项

把每个学生的住址也加进来

// 这种写法只会改变第一条数据
> db.student.update({}, {$set:{address: ''}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z") }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z") }

// 加上{multi:true},则是改变所有的数据项
// multi可取ture和false两个值,true代表全部修改,false代表只修改一个
> db.student.update({}, {$set:{address: ''}},{multi:true})
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 2 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "" }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

upsert选项

upsert选项作用是:在找不到的情况下,直接插入这条数据。

> db.student.update({name: 'zhaoliu'}, {$set: {age: 11}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "" }

// upsert也有两个值:true代表没有就添加,false代表没有不添加(默认值)
> db.student.update({name: 'zhaoliu'}, {$set: {age: 11}}, {upsert:true})
WriteResult({
	"nMatched" : 0,
	"nUpserted" : 1,
	"nModified" : 0,
	"_id" : ObjectId("5cbac8243ba35f60e25bffff")
})
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "" }
{ "_id" : ObjectId("5cbac8243ba35f60e25bffff"), "name" : "zhaoliu", "age" : 11 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

update数组修改器

$push修改器

$push的功能是追加数组中的值,但我们也经常用它操作内嵌稳文档,就是{}对象型的值。具体代码如下:

// 给lisi增加爱好4,是数组形式的
> db.student.update({name: 'lisi'}, {$push: {"hobby.hobbyFour": "台球"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球", "hobbyFour" : [ "台球" ] }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "" }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "" }
{ "_id" : ObjectId("5cbac8243ba35f60e25bffff"), "name" : "zhaoliu", "age" : 11, "score" : [ 89 ] }
1
2
3
4
5
6
7
8

$ne修改器

$ne修改器的主要作用是:检查一个值是否存在,如果不存在再执行操作,存在就不执行。

// 如果lisi的skill中没有开车,则添加
> db.student.update({name: 'lisi', skill:{$ne: '开车'}},{$push: {skill: '开车'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球", "hobbyFour" : [ "台球" ] }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "开车" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "", "skill" : [ ] }
{ "_id" : ObjectId("5cbac8243ba35f60e25bffff"), "name" : "zhaoliu", "age" : 11, "score" : [ 89 ], "skill" : [ ] }
1
2
3
4
5
6
7
8

总结:没有则修改,有则不修改。

$addToSet修改器

$addToSet$ne的升级版本,查找是否存在,不存在就push进去,操作起来更直观和方便,所以在工作中用的更多。

// 查看lisi有没有react技能,没有则添加
> db.student.update({name: 'lisi'}, {$addToSet: {skill:'react'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球", "hobbyFour" : [ "台球" ] }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "开车", "react" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "", "skill" : [ ] }
{ "_id" : ObjectId("5cbac8243ba35f60e25bffff"), "name" : "zhaoliu", "age" : 11, "score" : [ 89 ], "skill" : [ ] }
1
2
3
4
5
6
7
8

$each修改器

$each用于:批量添加,可以传入一个数组,一次增加多个值进去,相当于批量操作,性能同样比循环操作要好很多,这个是需要我们注意的,工作中也要先组合成数组,然后用批量的形式进行操作。

var tempSkill = ['react', 'vue', 'webpack']
1
// 同时给wangwu增加3个skill
> db.student.update({name: 'wangwu'}, {$addToSet:{skill:{$each:tempSkill}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球", "hobbyFour" : [ "台球" ] }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "开车", "react" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "react", "vue", "webpack" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "", "skill" : [ ] }
{ "_id" : ObjectId("5cbac8243ba35f60e25bffff"), "name" : "zhaoliu", "age" : 11, "score" : [ 89 ], "skill" : [ ] }
1
2
3
4
5
6
7
8

$pop修改器

$pop只删除一次,并不是删除所有数组中的值。而且它有两个选项,一个是1和-1。

  • 1:从数组末端进行删除
  • -1:从数组开端进行删除
// 删除wangwu的最后一项skill
> db.student.update({name: 'wangwu'},{$pop:{skill:1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球", "hobbyFour" : [ "台球" ] }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "开车", "react" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "react", "vue" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "", "skill" : [ ] }
{ "_id" : ObjectId("5cbac8243ba35f60e25bffff"), "name" : "zhaoliu", "age" : 11, "score" : [ 89 ], "skill" : [ ] }
1
2
3
4
5
6
7
8

数组定位修改

有时候只知道修改数组的第几位,但并不知道是什么,这时候我们可以使用数据项.int的形式。

// 修改wangwu的第2个skill为san,需要注意这里的计数是从0开始的
> db.student.update({name: 'wangwu'},{$set:{'skill.1':'san'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.student.find()
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"), "name" : "lisi", "age" : 20, "sex" : 0, "hobby" : { "hobbyTwo" : "足球", "hobbyThree" : "羽毛球", "hobbyOne" : "篮球", "hobbyFour" : [ "台球" ] }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "开车", "react" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6e"), "name" : "wangwu", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" }, "createTime" : ISODate("2019-04-20T06:33:15.407Z"), "address" : "", "skill" : [ "react", "san" ] }
{ "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6f"), "name" : "xiaohong", "age" : 10, "sex" : 0, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "createTime" : ISODate("2019-04-20T06:33:46.360Z"), "address" : "", "skill" : [ ] }
{ "_id" : ObjectId("5cbac8243ba35f60e25bffff"), "name" : "zhaoliu", "age" : 11, "score" : [ 89 ], "skill" : [ ] }
1
2
3
4
5
6
7
8

修改状态返回与安全

应答式写入

我们之前的操作都是非应答式写入,就是在操作完数据库后,数据库并没有给我们任何的回应和返回值,而是我们自己写了一句话print('The data was updated successfully');。这在工作中是不允许的,因为根本不能体现我们修改的结果。

应答式写入就会给我们直接返回结果,结果里边的包含项会很多,这样我们就可以很好的进行程序的控制和安全机制的处理。

db.runCommand()

db.runCommand()是数据库运行命令的执行器,执行命令首选就要使用它,因为它在Shell和驱动程序间提供了一致的接口。几乎所有的数据库操作,都可以使用runCommand命令来执行。现在我们试着用runCommand来修改数据库,看看结果和直接用db.collections.update有什么不同。

db.student.update({sex:1},{$set:{class:'三年级2班'}},false,true);
var resMsg = db.runCommand({getLastError:1});
printjson(resMsg);
1
2
3
> load('./demo6.js')
{
        "connectionId" : 48,
        "updatedExisting" : true, //该字段为true,说明操作成功了
        "n" : 4,
        "syncMillis" : 0,
        "writtenTo" : null,
        "err" : null,
        "ok" : 1
}
true
1
2
3
4
5
6
7
8
9
10
11
  • false:第一句末尾的false是upsert的简写,代表没有此条数据时不增加
  • true:true是multi的简写,代表修改所有,这两个我们在前边课程已经学过
  • getLastError:1:表示返回功能错误
  • printjson:表示以json对象的格式输出到控制台

db.listCommands():查看所有的Commad命令。

比如我们要查看是否和数据库链接成功了,就可以使用Command命令。

db.runCommand({ping:1})
1

返回ok:1就代表链接正常。

findAndModify

// demo7.js
const customModify = {
    findAndModify: 'student', // 指定要查找的集合
    query: {name: 'lisi'},
    update: {$set: {age: 24}},
    new: true, // 更新完成,需要查看结果,如果为false不进行查看结果
    // fields: {name: true, age: true, _id: false} // 只显示name和age
};
var resMsg = db.runCommand(customModify);
printjson(resMsg);
1
2
3
4
5
6
7
8
9
10
> load('./demo7.js')
{
        "lastErrorObject" : {
                "n" : 1,
                "updatedExisting" : true
        },
        "value" : {
                "_id" : ObjectId("5cbabd2b0712a21a9fdb3b6d"),
                "name" : "lisi",
                "age" : 24,
                "sex" : 0,
                "hobby" : {
                        "hobbyTwo" : "足球",
                        "hobbyThree" : "羽毛球",
                        "hobbyOne" : "篮球",
                        "hobbyFour" : [
                                "台球"
                        ]
                },
                "createTime" : ISODate("2019-04-20T06:33:15.407Z"),
                "address" : "",
                "skill" : [
                        "开车",
                        "react"
                ]
        },
        "ok" : 1
}
true
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

findAndModify属性值:

  • query:需要查询的条件/文档
  • sort:进行排序
  • update:查找到后进行相应的更新
  • remove:[boolean]是否删除查找到的文档,值为true,可以删除
  • new:[boolean]返回更新前的文档还是更新后的文档
  • fields:需要返回的字段
  • upsert:没有这个值是否增加

需要注意:update和remove只能同时存在一个。

查询find的不等修饰符

构造一些数据:

/**
 * 批量增加一些数据
 */
var student1 = {
    name: 'lisi',
    age: 10,
    sex: 1,
    hobby: {
        hobbyOne: '篮球',
        hobbyTwo: '足球',
        hobbyThree: '羽毛球'
    },
    skill: [],
    createTime: new Date()
};
var student2 = {
    name: 'wangwu',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '游泳',
        hobbyTwo: '健身',
        hobbyThree: '乒乓球'
    },
    skill: [],
    createTime: new Date()
};
var student3 = {
    name: 'xiaohong',
    age: 13,
    sex: 1,
    hobby: {
        hobbyOne: '瑜伽',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var student4 = {
    name: 'xiaohua',
    age: 12,
    sex: 0,
    hobby: {
        hobbyOne: '体操',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var student5 = {
    name: 'zhaoliu',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '音乐',
        hobbyTwo: '美术',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var student6 = {
    name: 'xiaoli',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '体操',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var student7 = {
    name: 'xiaoliu',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '钓鱼',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var student8 = {
    name: 'zhangsan',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '足球',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var student9 = {
    name: 'lihua',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '篮球',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var student10 = {
    name: 'xiaozhang',
    age: 12,
    sex: 1,
    hobby: {
        hobbyOne: '乒乓球',
        hobbyTwo: '跳舞',
        hobbyThree: '书法'
    },
    skill: [],
    createTime: new Date()
};
var db = connect('user');
var studentArr = [student1, student2, student3, student4, student5, student6, student7, student8, student9, student10];
db.student.insert(studentArr);
print('The data was inserted successfully');
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
> load('./demo8.js')
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
The data was inserted successfully
1
2
3
4

简单查找

// 查找hobbyOne是篮球的数据
> db.student.find({"hobby.hobbyOne": "篮球"})
{ "_id" : ObjectId("5cbaeef75328a836aca6e026"), "name" : "lisi", "age" : 10, "sex" : 1, "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "足球", "hobbyThree" : "羽毛球" }, "skill" : [ ], "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "_id" : ObjectId("5cbaeef75328a836aca6e02e"), "name" : "lihua", "age" : 12, "sex" : 1, "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" }, "skill" : [ ], "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
1
2
3
4

筛选字段

find的第二个参数可以用来指定返回的字段。

// 只显示name和hobby
> db.student.find( {"hobby.hobbyOne": "篮球"}, {name: true, hobby: true, _id: false} )
{ "name" : "lisi", "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "足球", "hobbyThree" : "羽毛球" } }
{ "name" : "lihua", "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
1
2
3
4

不等修饰符

  • 小于($lt):英文全称less-than
  • 小于等于($lte):英文全称less-than-equal
  • 大于($gt):英文全称greater-than
  • 大于等于($gte):英文全称greater-than-equal
  • 不等于($ne):英文全称not-equal
// 查年龄大于等于12,且小于等于14的学生
> db.student.find(
... {age:{$lte:14, $gte: 12}},
... {name: true, age: true, _id: false}
... )
{ "name" : "wangwu", "age" : 12 }
{ "name" : "xiaohong", "age" : 13 }
{ "name" : "xiaohua", "age" : 12 }
{ "name" : "zhaoliu", "age" : 12 }
{ "name" : "xiaoli", "age" : 12 }
{ "name" : "xiaoliu", "age" : 12 }
{ "name" : "zhangsan", "age" : 12 }
{ "name" : "lihua", "age" : 12 }
{ "name" : "xiaozhang", "age" : 12 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

日期筛选

> var startTime = new Date('01/01/2019')
// 筛选创建日期大于2019年1月1日的数据
> db.student.find( {createTime:{$gt:startTime}}, {name: true, age: true, createTime: true, _id: false} )
{ "name" : "lisi", "age" : 10, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "wangwu", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "xiaohong", "age" : 13, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "xiaohua", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "zhaoliu", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "xiaoli", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "xiaoliu", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "zhangsan", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "lihua", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
{ "name" : "xiaozhang", "age" : 12, "createTime" : ISODate("2019-04-20T10:05:43.190Z") }
1
2
3
4
5
6
7
8
9
10
11
12
13

find的多条件查询

$in修饰符

$in修饰符可以轻松解决一键多值的查询情况。和$in相对的修饰符是$nin,即查询除了$in条件以外的值。

// 查询年龄是10或者13的学生
> db.student.find(
    age: {$in:[10, 13]}},
    {name:1, age:1, _id:0}
)
{ "name" : "lisi", "age" : 10 }
{ "name" : "xiaohong", "age" : 13 }
1
2
3
4
5
6
7

$nin

> db.student.find( {age: {$nin:[10,13]}},{name:1,age:1,_id:0} )
{ "name" : "wangwu", "age" : 12 }
{ "name" : "xiaohua", "age" : 12 }
{ "name" : "zhaoliu", "age" : 12 }
{ "name" : "xiaoli", "age" : 12 }
{ "name" : "xiaoliu", "age" : 12 }
{ "name" : "zhangsan", "age" : 12 }
{ "name" : "lihua", "age" : 12 }
{ "name" : "xiaozhang", "age" : 12 }
1
2
3
4
5
6
7
8
9

$or修饰符

$or修饰符用来查询多个键值的情况,就比如查询学生中大于等于13岁或者hobbyOne是篮球,而$in修饰符是用于一个Key值的情况,相对应的还有$nor修饰符。

> db.student.find( {$or: [ {age: {$gte: 13}}, {"hobby.hobbyOne": "篮球"} ]}, {name:1,hobby:1,age:1,_id:0} )
{ "name" : "lisi", "age" : 10, "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "足球", "hobbyThree" : "羽毛球" } }
{ "name" : "xiaohong", "age" : 13, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
{ "name" : "lihua", "age" : 12, "hobby" : { "hobbyOne" : "篮球", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
1
2
3
4

$nor

// 筛选年龄小于13且hobbyOne不是篮球的学生
> db.student.find( {$nor: [ {age: {$gte: 13}}, {"hobby.hobbyOne": "篮球"} ]}, {name:1,hobby:1,age:1,_id:0} )
{ "name" : "wangwu", "age" : 12, "hobby" : { "hobbyOne" : "游泳", "hobbyTwo" : "健身", "hobbyThree" : "乒乓球" } }
{ "name" : "xiaohua", "age" : 12, "hobby" : { "hobbyOne" : "体操", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
{ "name" : "zhaoliu", "age" : 12, "hobby" : { "hobbyOne" : "音乐", "hobbyTwo" : "美术", "hobbyThree" : "书法" } }
{ "name" : "xiaoli", "age" : 12, "hobby" : { "hobbyOne" : "体操", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
{ "name" : "xiaoliu", "age" : 12, "hobby" : { "hobbyOne" : "钓鱼", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
{ "name" : "zhangsan", "age" : 12, "hobby" : { "hobbyOne" : "足球", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
{ "name" : "xiaozhang", "age" : 12, "hobby" : { "hobbyOne" : "乒乓球", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
1
2
3
4
5
6
7
8
9

$and修饰符

$and用来查找几个key值都满足的情况。

// 筛选年龄大于等于13且hobbyOne是篮球的学生
> db.student.find( {$and: [ {age: {$gte: 13}}, {"hobby.hobbyOne": "瑜伽"} ]}, {name:1,hobby:1,age:1,_id:0} )
{ "name" : "xiaohong", "age" : 13, "hobby" : { "hobbyOne" : "瑜伽", "hobbyTwo" : "跳舞", "hobbyThree" : "书法" } }
1
2
3

$not修饰符

$not修饰符用来查询除条件之外的值。

// 查询除了大于等于11,小于等于12的学生,即查询小于11或者大于12的学生
> db.student.find({
... age:{
... $not:{
... $lte:12,
... $gte:11
... }}},
... {name:1,age:1,_id:0})
{ "name" : "lisi", "age" : 10 }
{ "name" : "xiaohong", "age" : 13 }
1
2
3
4
5
6
7
8
9
10

find的数组查询

// 重新加载一遍数据
> load('./demo8.js')
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
The data was inserted successfully
true
1
2
3
4
5
6

基本数据查询

// 查询skill是['react','vue','css3']数据
> db.student.find(
... {skill:['react','vue','css3']},
... {name:1,skill:1,_id:0}
... )
{ "name" : "zhangsan", "skill" : [ "react", "vue", "css3" ] }
1
2
3
4
5
6

下面我们想查找skill中有react的学生。

db.student.find( {skill:['react']}, {name:1,skill:1,_id:0} )
1

运行后,并没有得到相应的学生数据。那问题出现在哪里呢?问题就在于:我们写了一个中括号([]),加上中括号就相当于完全匹配了,所以没有得到一条符合查询条件的数据,我们去掉中括号再看看结果。

> db.student.find( {skill:'react'}, {name:1,skill:1,_id:0} )
{ "name" : "wangwu", "skill" : [ "jquery", "react", "html" ] }
{ "name" : "zhangsan", "skill" : [ "react", "vue", "css3" ] }
1
2
3

以上就是我们在数组中查询一项的方法。

$all修饰符

$all修饰符用于数据多项查询。

// 查询skill中既有react和vue的学生
> db.student.find( {skill:{$all:['react','vue']}}, {name:1,skill:1,_id:0} )
{ "name" : "zhangsan", "skill" : [ "react", "vue", "css3" ] }
1
2
3

$in修饰符

$all修饰符,是需要满足所有条件才可以,$in修饰符是只要满足数组中的一项就可以被查出来(有时候会跟$or弄混)。

// 查询skill中有react或者vue的学生
> db.student.find( {skill:{$in:['react','vue']}}, {name:1,skill:1,_id:0} )
{ "name" : "wangwu", "skill" : [ "jquery", "react", "html" ] }
{ "name" : "xiaohong", "skill" : [ "vue", "css", "html" ] }
{ "name" : "zhangsan", "skill" : [ "react", "vue", "css3" ] }
1
2
3
4
5

$size修饰符

$size修饰符可以根据数组长度来检索。

// 查询skill有5项的学生
> db.student.find( {skill:{$size:5}}, {name:1,skill:1,_id:0} )
{ "name" : "wangwu", "skill" : [ "san", "vue", "jquery", "react", "html" ] }
1
2
3

$slice修饰符

只显示每个学生的skill的前两项。

> db.student.find(
... {},
... {name:1,skill:{$slice:2},age:1,_id:0}
... )
{ "name" : "lisi", "age" : 10, "skill" : [ "js", "css" ] }
{ "name" : "wangwu", "age" : 12, "skill" : [ "san", "vue" ] }
{ "name" : "xiaohong", "age" : 13, "skill" : [ "vue", "css" ] }
{ "name" : "xiaohua", "age" : 12, "skill" : [ "webpack", "node" ] }
{ "name" : "zhaoliu", "age" : 12, "skill" : [ "node", "js" ] }
{ "name" : "xiaoli", "age" : 12, "skill" : [ "http", "npm" ] }
{ "name" : "xiaoliu", "age" : 12, "skill" : [ "ES6", "ES7" ] }
{ "name" : "zhangsan", "age" : 12, "skill" : [ "react", "vue" ] }
{ "name" : "lihua", "age" : 12, "skill" : [ "san", "echarts" ] }
{ "name" : "xiaozhang", "age" : 12, "skill" : [ "ES6", "css3" ] }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

只显示每个学生的skill的最后一项。

> db.student.find( {}, {name:1,skill:{$slice:-1},age:1,_id:0} )
{ "name" : "lisi", "age" : 10, "skill" : [ "html" ] }
{ "name" : "wangwu", "age" : 12, "skill" : [ "html" ] }
{ "name" : "xiaohong", "age" : 13, "skill" : [ "html" ] }
{ "name" : "xiaohua", "age" : 12, "skill" : [ "html" ] }
{ "name" : "zhaoliu", "age" : 12, "skill" : [ "webpack" ] }
{ "name" : "xiaoli", "age" : 12, "skill" : [ "html5" ] }
{ "name" : "xiaoliu", "age" : 12, "skill" : [ "ES8" ] }
{ "name" : "zhangsan", "age" : 12, "skill" : [ "css3" ] }
{ "name" : "lihua", "age" : 12, "skill" : [ "html5" ] }
{ "name" : "xiaozhang", "age" : 12, "skill" : [ "html5" ] }
1
2
3
4
5
6
7
8
9
10
11

find的参数使用方法

find参数:

  • query:这个是查询条件,MongoDB默认的第一个参数;
  • fields:需要返回的字段,可以用true和false控制是否显示;
  • limit:返回的数量,后边跟数字,控制每次查询返回的结果数量;
  • skip:跳过多少个显示,和limit结合可以实现分页;
  • sort:排序方式,1代表升序,-1代表降序;

模拟分页

> db.student.find( {}, {name:1,age:1,_id:0}).skip(1).limit(3).sort({'age':-1})
{ "name" : "wangwu", "age" : 12 }
{ "name" : "xiaohua", "age" : 12 }
{ "name" : "zhaoliu", "age" : 12 }
1
2
3
4

需要注意:skip(),limit(),sort()三个方法放在一起执行的时候,执行顺序是先sort(),然后是skip(),最后是limit()。

$where修饰符

// 查询年龄大于12的学生
> db.student.find(
... {$where:"this.age>12"},
... {name:1,age:1,_id:0}
... )
{ "name" : "xiaohong", "age" : 13 }
1
2
3
4
5
6

这里的this指向的是student集合本身。这样我们就可以在程序中随意调用。虽然强大和灵活,但是这种查询对于数据库的压力和安全性都会变重,所以在工作中尽量减少$where修饰符的使用。

find如何在js文本中使用

hasNext循环结果

var db = connect('user');  // 链接数据库
var result = db.student.find(); // 声明变量result,并把查询结果赋值给result
// 利用游标的hasNext()进行循环输出结果
while (result.hasNext()) {
    printjson(result.next());  // 用json格式打印结果
}
1
2
3
4
5
6
> load('./hasNext.js')
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
{
        "_id" : ObjectId("5cbb06aa5328a836aca6e03a"),
        "name" : "lisi",
        "age" : 10,
        "sex" : 1,
        "hobby" : {
                "hobbyOne" : "篮球",
                "hobbyTwo" : "足球",
                "hobbyThree" : "羽毛球"
        },
        "skill" : [
                "js",
                "css",
                "html"
        ],
        "createTime" : ISODate("2019-04-20T11:46:50.291Z")
}
...
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

forEach循环结果

forEach.js

var db = connect('user');  // 链接数据库
var result = db.student.find(); // 声明变量result,并把查询结果赋值给result
result.forEach(result => printjson(result));
1
2
3
// 执行即可看到结果
load('./forEach.js')
1
2

索引

构造百万级数据

索引的性能体现必须要有大量数据才能看出来,如果说只有有10条20条数据,是根本看不出来效果的,我们首先通过随机数的方法,构造出一个百万级数据的数据库出来。

//生成随机数
function createRandomNum(min, max) {
    let range = max-min;   // 得到随机数区间
    let rand = Math.random(); // 得到随机值
    return (min + Math.round(rand *range)); // 最小值+随机数取整
}

// console.log(createRandomNum(10000, 99999));

// 生成随机用户名
function createRandomUserName(min, max){
    let tempStringArray= "123456789qwertyuiopasdfghjklzxcvbnm".split('');//构造生成时的字母库数组
    let outPutText = ''; //最后输出的变量
    //进行循环,随机生产用户名的长度,这里需要生成随机数方法的配合
    for(let i=1; i < createRandomNum(min, max); i++) {
        //随机抽取字母,拼装成需要的用户名
        outPutText = outPutText + tempStringArray[createRandomNum(0,tempStringArray.length)];
    }
    return outPutText;
}

// console.log(createRandomUserName(7, 16));
// var startTime=(new Date()).getTime();
var db = connect('user');
db.randomInfo.drop();
var tempInfo = [];
for (let i = 0; i < 2000000; i++) {
    tempInfo.push({
        username: createRandomUserName(7, 16),
        regeditTime: new Date(),
        randNum0: createRandomNum(100000,999999),
        randNum1: createRandomNum(100000,999999),
        randNum2: createRandomNum(100000,999999),
        randNum3: createRandomNum(100000,999999),
        randNum4: createRandomNum(100000,999999),
        randNum5: createRandomNum(100000,999999),
        randNum6: createRandomNum(100000,999999),
        randNum7: createRandomNum(100000,999999),
        randNum8: createRandomNum(100000,999999),
        randNum9: createRandomNum(100000,999999),
    })
}

db.randomInfo.insert(tempInfo);
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
> load('./createRandomUser.js')
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
true
1
2
3
4
// 查看数据量
> db.randomInfo.stats().count
2000000
>
1
2
3
4

普通查询性能

200万数据普通检索:

var startTime = new Date().getTime(); // 得到程序开始运行的时间
var db = connect('user'); // 链接数据库
var res = db.randomInfo.find({username: '5pnyce'}); // 根据用户名查找用户
res.forEach(item => printjson(item)); // 循环输出
var runTime = new Date().getTime() - startTime; // 得到程序运行时间
print('This run time is: ' + runTime + 'ms');  //打印出运行时间
1
2
3
4
5
6
> load('./customSearch.js')
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
{
        "_id" : ObjectId("5cbb16755328a836aca866f9"),
        "username" : "5pnyce",
        "regeditTime" : ISODate("2019-04-20T12:54:01.742Z"),
        "randNum0" : 725085,
        "randNum1" : 401201,
        "randNum2" : 600271,
        "randNum3" : 145201,
        "randNum4" : 292000,
        "randNum5" : 511782,
        "randNum6" : 915503,
        "randNum7" : 427219,
        "randNum8" : 513973,
        "randNum9" : 246754
}
This run time is: 3779ms
true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

从上面运行结果来看,大概需要3.7秒,这个时间是没办法满足我们的日常查询的。

创建索引

数据量少的时候,不使用索引查询速度还是很快的;但是当数据量较大时,不使用索引的话查询速度将会变的很慢。

// 查看当前集合的索引,目前只有一个_id_索引
> db.randomInfo.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "user.randomInfo"
	}
]
>
1
2
3
4
5
6
7
8
9
10
11
12
13

MongoDB使用ensureIndex({key: 1})方法来创建索引:

key为我们要创建的索引字段,1为按升序创建索引,-1为按降序创建索引。 也可以设置使用多个字段创建索引(关系型数据库中称作复合索引) db.col_name.ensureIndex({key:1})。需要注意的是:3.0版本后推荐使用createIndex()来创建索引。

为用户名username建立索引:

> db.randomInfo.ensureIndex({username:1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1 // 说明创建索引成功了
}
1
2
3
4
5
6
7
// 再次查看索引
> db.randomInfo.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "user.randomInfo"
	},
	{
		"v" : 2,
		"key" : {
			"username" : 1
		},
		"name" : "username_1",
		"ns" : "user.randomInfo"
	}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

重新查询:

> load('./customSearch.js')
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
{
        "_id" : ObjectId("5cbb16755328a836aca866f9"),
        "username" : "5pnyce",
        "regeditTime" : ISODate("2019-04-20T12:54:01.742Z"),
        "randNum0" : 725085,
        "randNum1" : 401201,
        "randNum2" : 600271,
        "randNum3" : 145201,
        "randNum4" : 292000,
        "randNum5" : 511782,
        "randNum6" : 915503,
        "randNum7" : 427219,
        "randNum8" : 513973,
        "randNum9" : 246754
}
This run time is: 25ms
true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

只需要25ms,查询性能大大提升。

总结:无论是在关系型数据库还是非关系型数据库,建立索引都是非常重要的。但是,需要注意的是:索引是要消耗硬盘和内存资源的,所以还是要根据程序需要进行建立了。MongoDB也给我们进行了限制,只允许我们建立64个索引值。

复合索引

复合索引简单理解就是:两条以上的索引。

不用索引的情况:

  • 数据不超万条时,不需要使用索引。性能的提升并不明显,而且大大增加了内存和硬盘的消耗;
  • 查询数据超过表数据量30%时,不要使用索引字段查询。实际证明会比不使用索引更慢,因为它大量检索了索引表和我们原表;
  • 数字索引,要比字符串索引快的多,在百万级甚至千万级数据量面前,使用数字索引是个明确的选择;
  • 把我们经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引

现在把randNum0这个字段也设置成索引。

> db.randomInfo.ensureIndex({randNum0:1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 2,
	"numIndexesAfter" : 3,
	"ok" : 1
}
1
2
3
4
5
6
7

一共有三个索引,两个自建索引username和randNum0

> db.randomInfo.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "user.randomInfo"
	},
	{
		"v" : 2,
		"key" : {
			"username" : 1
		},
		"name" : "username_1",
		"ns" : "user.randomInfo"
	},
	{
		"v" : 2,
		"key" : {
			"randNum0" : 1
		},
		"name" : "randNum0_1",
		"ns" : "user.randomInfo"
	}
]
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
/**
 * 200万数据复合索引检索
 */
var startTime = new Date().getTime(); // 得到程序开始运行的时间
var db = connect('user'); // 链接数据库
var res = db.randomInfo.find({username: 'n7wl5kq', randNum0: 754417}); // 根据用户名和randNum0查找用户
res.forEach(item => printjson(item)); // 循环输出
var runTime = new Date().getTime() - startTime; // 得到程序运行时间
print('This run time is: ' + runTime + 'ms');  //打印出运行时间
1
2
3
4
5
6
7
8
9
> load('./customSearch.js')
connecting to: mongodb://127.0.0.1:27017/user
MongoDB server version: 3.6.3
{
        "_id" : ObjectId("5cbb16755328a836aca866fb"),
        "username" : "n7wl5kq",
        "regeditTime" : ISODate("2019-04-20T12:54:01.742Z"),
        "randNum0" : 754417,
        "randNum1" : 405438,
        "randNum2" : 513075,
        "randNum3" : 888891,
        "randNum4" : 586031,
        "randNum5" : 704484,
        "randNum6" : 906708,
        "randNum7" : 303593,
        "randNum8" : 164085,
        "randNum9" : 589671
}
This run time is: 20ms
true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

查询时间还是在20ms左右。MongoDB的复合查询是按照我们的索引顺序进行查询的。就是我们用db.randomInfo.getIndexes()查询出的数组。

hint方法指定索引查询

我们都知道数字索引要比字符串索引快,这就需要一个方法来打破索引表的查询顺序,优先使用我们自己指定的索引查询,这个方法就是hint().

var res = db.randomInfo.find({username: 'n7wl5kq', randNum0: 754417}).hint({randNum0:1});
1

由于数据量和复杂程度还是不大,所以我们看不出来明显的性能提升,但是,当我们在工作中遇到大数据时,一定会得到很好的效果。

删除索引

当索引性能不佳或起不到作用时,我们需要删除索引,删除索引的命令是dropIndex()

db.randomInfo.dropIndex('randNum0_1'); //索引的唯一ID
1

需要注意的是:删除索引时填写的值,并不是我们的字段名称(key,即randNum0),而是我们索引查询表中的name值。

全文索引

准备数据:

db.info.insert({contextInfo:"I am a student. I love learning. I am good at playing basketball and football. I love my family, I love my parents."})
db.info.insert({contextInfo:"I am a research and development engineer. I love working and studying. I love my family, I love my parents."})
1
2

建立全文索引

db.info.ensureIndex({contextInfo:'text'})
1

需要注意的是:这里使用text关键词来代表全文索引,就不建立数据模型了。

全文索引查找

建立好了全文索引,就可以查找了,查找时需要两个关键修饰符:

  • $text:表示要在全文索引中查东西
  • $search:后边跟查找的内容
> db.info.find({$text:{$search:"student"}})
{ "_id" : ObjectId("5cbb3105466a2bd461ae0f42"), "contextInfo" : "I am a student. I love learning. I am good at playing basketball and football. I love my family, I love my parents." }
1
2

查找多个词

全文索引支持多个词语查找,比如我们希望查找数据中有student engineer learning的数据(这是或的关系),所以两条数据都会出现。

> db.info.find({$text:{$search:"student engineer learning"}})
{ "_id" : ObjectId("5cbb3107466a2bd461ae0f43"), "contextInfo" : "I am a research and development engineer. I love working and studying. I love my family, I love my parents." }
{ "_id" : ObjectId("5cbb3105466a2bd461ae0f42"), "contextInfo" : "I am a student. I love learning. I am good at playing basketball and football. I love my family, I love my parents." }
1
2
3

如果我们这时候希望不查找出来有learning这个单词的记录,我们可以使用-减号来取消。

db.info.find({$text:{$search:"student engineer -learning"}})
1

转义符:全文索引中是支持转义符的,比如我们想搜索的是两个词(love learning和development),这时候需要使用\斜杠来转义。

> db.info.find({$text:{$search:"\'love learning\' development"}})
{ "_id" : ObjectId("5cbb3107466a2bd461ae0f43"), "contextInfo" : "I am a research and development engineer. I love working and studying. I love my family, I love my parents." }
{ "_id" : ObjectId("5cbb3105466a2bd461ae0f42"), "contextInfo" : "I am a student. I love learning. I am good at playing basketball and football. I love my family, I love my parents." }
1
2
3

总结:全文索引在工作还是经常使用的,比如博客文章的搜索,长文件的关键词搜索,这些都需要使用全文索引来进行。

备份和还原

MongoDB数据库的备份和还原依赖mongodump和mongorestore两个命令,这两个命令直接在命令行执行就可以了,不需要在mongo命令行中。

数据备份

mongodump备份的基本格式如下所示,其实就是一条在终端中执行的命令。

mongodump
    --host 127.0.0.1
    --port 27017
    --out /Users/liujie26/backup  // 备份数据的目录
    --collection student // 要备份的集合
    --db user // 要备份的数据库
    --username username // 当前操作的用户
    --password password
1
2
3
4
5
6
7
8

比如现在我们备份所有MongoDB里的数据库到/Users/liujie26/backup文件夹下,命令如下:

mongodump --host 127.0.0.1 --port 27017 --out /Users/liujie26/backup
1

数据恢复

备份好后,如果数据库有意外或者遭受到了攻击,我们要进行恢复数据库,这时候就可以使用mongorestore命令。具体格式如下:

mongorestore
    --host 127.0.0.1
    --port 27017
    --username username
    --password password
    <path to the backup> // 备份数据所在目录
1
2
3
4
5
6

比如我们现在不小心删除了一个collections的数据,要进行恢复。现在删除randomInfo集合。

// 先删除指定集合
> db.randomInfo.drop()
true
// 删除后查询集合确实被删除
> show collections
books
info
login
people
student
test
users

// 恢复被删除集合数据
mongorestore --host 127.0.0.1 --port 27017 /Users/liujie26/backup

// 恢复后查询集合数据确实被恢复
> show collections
books
info
login
people
randomInfo
student
test
users
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

总结:两个命令很简单,甚至我们可以写成脚本和定时任务,让它每天自己执行。但是如果我们真的使用了MongoDB数据库,这是一个最基本的操作,还是要会使用的。

参考文档

  1. MongoDB 基础(六)安全性(权限操作)