数据库存储了大量的数据,当我们需要特定的数据时就要使用查询方法,根据一定的条件,筛选出我们想要的数据,前一章我们简单介绍了条件操作符(<
、<=
、>
、>=
、!=
等),在这一章中我们将更全面地介绍 MongoDB 中的文档查询方法。
一、数据的导入导出
任务描述
本关任务:向数据库导入数据和从数据库导出数据。
相关知识
为了完成本关任务,你需要掌握: 1.如何向数据库导入数据; 2.如何从数据库导出数据。
向数据库导入数据
数据导入工具:mongoimport;
这是 MongoDB 自带的数据导入工具,我们在未连接客户端时使用(前提要启动服务)。
mongoimport -d Testdb1 -c score --type csv --headerline --ignoreBlanks --file test.csv
-d Testdb1 :指定将数据导入到 Testdb1 数据库;
-c score :将数据导入到集合 score ,如果这个集合之前不存在,会自动创建一个(如果省略 --collection 这个参数,那么会自动新建一个以 CSV 文件名为名的集合);
--type csv :文件类型,这里是 CSV;
--headerline :这个参数很重要,加上这个参数后创建完成后的内容会以 CSV 文件第一行的内容为字段名(导入json文件不需要这个参数);
--ignoreBlanks :这个参数可以忽略掉 CSV 文件中的空缺值(导入json文件不需要这个参数);
--file 1.csv :这里就是 CSV 文件的路径了,需要使用绝对路径。
从数据库导出数据
数据导出工具: mongoexport;
- 导出 json 格式文件:
mongoexport -d Testdb1 -c score -o /file.json --type json
- -o /file.json :输出的文件路径
/
(根目录下)和文件名;- --type json :输出的格式,默认为 json。
- 导出 csv 格式的文件:
mongoexport -d Testdb1 -c score -o /file.json --type csv -f "_id,name,age,sex,major"
- -f :当输出格式为 csv 时,需要指定输出的字段名。
编程要求
在右侧命令行进行操作:
將 /home/example 路径下的文件 student.csv 导入到数据库 mydb1 的 test 集合中;
将数据库 mydb1 的 test 集合以 json 格式导出到 /home/test1.json 的 json 文件中;
将数据库 mydb1 的 test 集合以 csv 格式导出到 /home/test1.csv 的 CSV 文件中。
root@evassh-12318384:~# mongoimport -d mydb1 -c test --type csv --headerline --ignoreBlanks --file /home/example/student.csv
2022-09-24T04:43:06.805+0000 connected to: localhost
2022-09-24T04:43:06.843+0000 imported 8 documents
root@evassh-12318384:~# mongoexport -d mydb1 -c test -o /home/test1.json --type json
2022-09-24T04:44:52.781+0000 connected to: localhost
2022-09-24T04:44:52.782+0000 exported 8 records
root@evassh-12318384:~# mongoexport -d mydb1 -c test -o /home/test1.csv --type csv -f "_id,name,age,sex,major"
2022-09-24T04:47:03.379+0000 connected to: localhost
2022-09-24T04:47:03.379+0000 exported 8 records
二、高级查询(一)
任务描述
本关任务:根据编程要求完成文档查询。
相关知识
为了完成本关任务,你需要掌握:各种查询操作符的用法。
$all 匹配所有
假设有集合 hobbies 内容如下:
_id name sex hobbies 1 小红 女 唱歌,跳舞,羽毛球 2 小明 男 唱歌,乒乓球,羽毛球 3 小亮 男 乒乓球,羽毛球 查询其中所有喜欢“唱歌”和“羽毛球”的人:1
db.hobbies.find({hobbies:{$all:["唱歌","羽毛球"]})
查询结果如图1所示:
图 1
- $all 会查询满足方括号中所有条件的文档,如果只有其中一项满足是不会被查询出来的。
$exists 判断字段是否存在
在集合 hobbies 中更新文档:
db.hobbies.save({_id:1,name:"小红",age:18,sex:"女",hobbies:["唱歌","跳舞","羽毛球"]}) #添加小红年龄18
- 查询 hobbies 集合中存在 age 字段的文档,如图 2 所示:
图 2
- hobbies 集合中不存在 age 字段的文档,如图 3 所示:
图 3
$mod 取模运算
在集合 hobbies 中更新文档:
db.hobbies.update({_id:2},{$set:{age:20}}) #添加小明年龄20 db.hobbies.update({_id:3},{$set:{age:22}}) #添加小亮年龄22
查询 age 取模7等于4的文档:
db.hobbies.find({age:{$mod:[7,4]}})
查询结果如如图4所示::
图 4
$in 包含
查询 age =17或 age =20的文档 :
db.hobbies.find({age:{$in:[17,20]}})
查询结果如图5所示:
图 5
$nin 不包含
查询 age !=17且 age !=20的文档:
db.hobbies.find({age:{$nin:[17,20]}})
查询结果如图6所示:
图 6
$size 数组元素个数
可以查询特定长度的数组,比如 hobbies 这一字段,查询有两个爱好的文档:
db.hobbies.find({hobbies:{$size:2}})
查询结果如图7所示:
图 7
查询结果排序
查询结果排序语法如下:
db.collection.find().sort({_id:1}) #将查询结果按照_id升序排序 db.collection.find().sort({_id:-1}) #将查询结果按照_id降序排序
编程要求
现有 person.json 文件内容如下:
_id name age sex hobbies 1 杨璐 19 女 唱歌,跳舞 2 李建学 20 男 唱歌,篮球 …… …… …… …… …… 在命令行进行操作:
- 将 /home/example/person.json 文件导入到数据库 mydb2 中的 test 集合中。
在右侧代码行 Begin-End 中编辑:
执行查询命令,查找所有喜欢唱歌和跳舞的人的信息,并按照
_id
升序排序;执行查询命令,查找所有喜欢羽毛球和跳舞的人的信息,并按照
_id
升序排序;执行查询命令,查找有3个爱好的人的信息,并按照
_id
升序排序;执行查询命令,查找文档中存在 hobbies 字段的人的信息,并按照
_id
升序排序;执行查询命令,查找19岁和23岁的人的信息,并按照
_id
升序排序;执行查询命令,查找不是20岁的人的信息,并按照
_id
升序排序;执行查询命令,查找 age 取模9等于2的人的信息,并按照
_id
升序排序。注意:上述操作共有七条命令,每条命令以
;
号隔开(由于测试需要,请在$
前加\
(转义符),即使用\$
,平时在命令窗口练习不需要加\
;不要使用双引号改用 单引号)。
mongoimport -d mydb2 -c test --type json --file /home/example/person.json
echo “db.test.find({hobbies:{\$all:[‘唱歌’,’跳舞’]}}).sort({_id:1});
db.test.find({hobbies:{\$all:[‘羽毛球’,’跳舞’]}}).sort({_id:1});
db.test.find({hobbies:{\$size:3}}).sort({_id:1});
db.test.find({hobbies:{\$exists:true}}).sort({_id:1});
db.test.find({age:{\$in:[19,23]}}).sort({_id:1});
db.test.find({age:{\$nin:[20]}}).sort({_id:1});
db.test.find({age:{\$mod:[9,2]}}).sort({_id:1});”
三、高级查询(二)
任务描述
本关任务:根据编程要求完成文档查询。
相关知识
为了完成本关任务,你需要掌握:各种查询操作符的用法。
假设数据库有集合 student 如下:
_id name age sex major 1 王晓丽 19 女 计算机 2 张明 21 男 计算机 3 秋雅 20 女 播音主持 4 张欣欣 18 女 表演 $or 条件之间的或查询
$or 表示多个查询条件之间是或的关系,比如查询性别 sex 为 男 或年龄 age 为18的文档信息:
db.student.find({$or:[{sex:"男"},{age:18}]})
查询结果,如图1所示:
图 1
$and 条件之间的且查询
$and
表示多个查询条件之间是且的关系,比如查询年龄 age 大于18且小于21(18 < age < 21
)的信息:db.student.find({$and:[{age:{$gt:18}},{age:{$lt:21}}]})
查询结果,如图2所示:
图 2
$not 条件取反查询
$not 用来执行取反操作,比如查询年龄 age 大于等于20岁,然后进行取反(即查询年龄小于20岁的文档):
db.student.find({age:{$not:{$gte:20}}})
查询结果,如图3所示:
图 3
正则表达式匹配查询
查询不符合
major=计*
开头文档:db.student.find({major:{$not:/^计.*/}})
查询结果,如图4所示:
图 4
count() 返回结果集总数
比如返回上一步正则查询到的结果集有几条:
db.student.find({major:{$not:/^计.*/}}).count()
查询结果,如图5所示:
图 5
编程要求
现有 person.json 文件内容如下:
_id name age sex hobbies 1 杨璐 19 女 唱歌,跳舞 2 李建学 20 男 唱歌,篮球 …… …… …… …… …… 在右侧命令行进行操作:
- 将 /home/example/person.json 文件导入到数据库 mydb3 中的 test 集合中。
在右侧代码行 Begin-End 中编辑,如下:
执行查询命令,查找年龄为20岁男生的信息,并按照
_id
升序排序;执行查询命令,查找年龄为20岁或者性别为男生的信息,并按照
_id
升序排序;执行查询命令,查找
name = 韩*
开头的人的信息,并按照_id
升序排序;执行查询命令,查找年龄
19 =< age < 22
的人的信息,并按照_id
升序排序;执行查询命令,查找年龄
age < 19
或age >21
的信息,并按照_id
升序排序;执行查询命令,查找
name != 韩*
开头的人的信息,并按照_id
升序排序;执行查询命令,查找查找
name != 韩*
开头的人的个数;执行查询命令,查找年龄
19 =< age < 22
的人的个数。注意:上述操作共有八条命令,每条命令以
;
号隔开(由于测试需要,请在$
前加\
(转义符),即使用\$
,平时在命令窗口练习不需要加\
;不要使用双引号改用 单引号)。
#********* Begin *********#
echo "
db.test.find({'age': 20, 'sex': '男'}).sort({_id: 1});
db.test.find({\$or: [{age: 20}, {sex: '男'}]}).sort({_id: 1});
db.test.find({name: /^韩/}).sort({_id: 1});
db.test.find({age: {\$gte: 19, \$lt: 22}}).sort({_id: 1});
db.test.find({\$or:[{age:{\$lt:19}},{age:{\$gt:21}}]}).sort({_id:1});
db.test.find({name: {\$not: /^韩/}}).sort({_id: 1});
db.test.count({name: {\$not: /^韩/}});
db.test.count({age: {\$gte: 19, \$lt: 22}});
"
#********* End *********#
四、游标
任务描述
本关任务:按照编程要求在命令行进操作,使用游标插入文档。
相关知识
db.collection.find() 可以实现根据条件查询和指定使用投影运算符返回的字段省略此参数返回匹配文档中的所有字段。并返回到匹配文档的游标,可以随意修改查询限制、跳跃、和排序顺序的功能。
为了完成本关任务,你需要掌握: 1.什么是游标; 2.如何使用游标。
什么是游标
通俗的说,游标不是查询结果,而是查询的返回资源,或者接口。通过这个接口,你可以逐条读取。就像 fopen 打开文件,得到一个资源一样,通过资源,可以一行一行的读文件。
使用循环插入数据
我们首先插入10000条数据到集合 items,因为 mongodb 底层是 javascript 引擎,所以我们可以使用 js 的语法来插入数据:
for(var i=0;i<10000;i++)db.items.insert({_id:i,text:"Hello MongoDB"+i})
插入后查看效果,如图1所示:
图 1
声明游标
定义一个变量来保存这个游标,find 的查询结果(
_id<=5
)赋值给了游标 cursor 变量,代码如下:var cursor=db.items.find({_id:{$lte:5}})
打印游标中的数据信息
有四种方法进行打印:
- printjson(cursor.next()) 打印下一条数据,如图 2 所示:
图 2
注意:当取完游标中的数据,又进行打印,会报错。
- 使用 js 的 while 语法来循环打印,具体步骤如图 3 所示:
图 3
- 使用 for 循环打印,具体步骤如图 4 所示:
图 4
- 使用 forEach 打印,具体步骤如图 5 所示:
图 5
游标的使用场景
我们可以在分页的情况下使用游标。
假设每页有10行,我们查询第701页,可以配合 skip() 和 limit() 来实现,具体步骤如图6所示:
图 6
如果不想全部取出,只取出某一个,可以使用如下方法,取出数组下标,具体步骤如图7所示:
图 7
编程要求
在命令行进行以下操作:
- 在数据库 mydb4 中,向集合 test 循环插入 10000 条数据,格式如下:
_id title content 1 MongoDB1 hello1 2 MongoDB2 hello2 3 MongoDB3 hello3 …… …… ……
- 将集合 test 以 csv 格式导出到 /home/test/test4.csv 文件中。
打印游标中的数据信息请自行练习尝试,测评不做要求。
> use mydb4
switched to db mydb4
> for(var i=0;i<10000;i++)db.test.insert({_id:i,title:"MongoDB"+i,content:"hello"+i})
WriteResult({ "nInserted" : 1 })
> exit
bye
root@evassh-12318384:~# mongoexport -d mydb4 -c test -o /home/test/test4.csv --type csv -f "_id,title,content"
2022-09-29T00:42:15.346+0000 connected to: localhost
2022-09-29T00:42:15.427+0000 exported 10000 records