MongoDB 数据库 title: mongoDB
MongoDB 数据库学习与实践[TOC]
一、MongoDB 介绍 :airplane:
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
1.1 主要特点
- MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。
- 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName="Sameer",Address="8 Gandhi Road")来实现更快的排序。
- 你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。
- 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。
- Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
- MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
- Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。
- Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。
- Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
- GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
- MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
- MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
- MongoDB安装简单。
二、 MongoDB 相关概念:flipper:
2.1 相关概念
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
Mon共DB的数据类型:
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
2.2 ObjectId
ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:
- 前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时
- 接下来的 3 个字节是机器标识码
- 紧接的两个字节由进程 id 组成 PID
- 最后三个字节是随机数
MongoDB 中存储的文档必须有一个 _id 键。这个键的值可以是任何类型的,默认是个 ObjectId 对象
由于 ObjectId 中保存了创建的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:
> var newObject = ObjectId()
> newObject.getTimestamp()
ISODate("2017-11-25T07:21:10Z")
bjectId 转为字符串
> newObject.str
5a1919e63df83ce79df8b38f
2.3 mongodb 的连接
标准 URI 连接语法:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
- mongodb:// 这是固定的格式,必须要指定。
- username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登录这个数据库
- host1 必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。
- portX 可选的指定端口,如果不填,默认为27017
- /database 如果指定username:password@,连接并验证登录指定数据库。若不指定,默认打开 test 数据库。
- ?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&或;(分号)隔开
标准的连接格式包含了多个选项(options),如下所示:
选项 | 描述 |
---|---|
replicaSet=name | 验证replica set的名称。 Impliesconnect=replicaSet. |
slaveOk=true|false | true:在connect=direct模式下,驱动会连接第一台机器,即使这台服务器不是主。在connect=replicaSet模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器。false: 在 connect=direct模式下,驱动会自动找寻主服务器. 在connect=replicaSet 模式下,驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器。 |
safe=true|false | true: 在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功。(还要参考 wtimeoutMS).false: 在每次更新之后,驱动不会发送getLastError来确保更新成功。 |
w=n | 驱动添加 { w : n } 到getLastError命令. 应用于safe=true。 |
wtimeoutMS=ms | 驱动添加 { wtimeout : ms } 到 getlasterror 命令. 应用于 safe=true. |
fsync=true|false | true: 驱动添加 { fsync : true } 到 getlasterror 命令.应用于 safe=true.false: 驱动不会添加到getLastError命令中。 |
journal=true|false | 如果设置为 true, 同步到 journal (在提交到数据库前写入到实体中). 应用于 safe=true |
connectTimeoutMS=ms | 可以打开连接的时间。 |
socketTimeoutMS=ms | 发送和接受sockets的时间。 |
使用用户名和密码连接登录到指定数据库,格式如下:
mongodb://admin:123456@localhost/test
三、MongoDB相关集合指令 :taco:
3.1 相关数据库指令指令
// -- 创建数据库
use info_db
//-- 删除数据库
db.dropDatabase()
//-- 创建集合
db.createCollection("item_wg")
// -- 删除集合
db.item_wg.drop()
//
// -- 插入文档
db.item_wg.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
// -- 查询文档
db.item_wg.find()
// -- 更新文档
db.item_wg.update({'name':'zhangsan'},{$set:{'title':'python'}})
// -- 修改多条相同文档
db.item_wg.update({'title':'MongoDB'},{$set:{'title':'MongoDB教程'}},{multi:true})
// -- save 方法替换文档
db.item_wg.save({
"_id" : ObjectId("6406994f79694e763e732f92"),
"title" : "MongoDB",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "Runoob",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"NoSQL"
],
"likes" : 110
})
// -- 删除文档 删除查找到1条
db.item_wg.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
// -- 删除1条
db.item_wg.remove({'title':'MongoDB 教程'},{'justOne':true})
db.item_wg.deleteOne('title':'MongoDB 教程'})
// -- 删除全部
db.item_wg.remove({'title':'MongoDB 教程'})
db.item_wg.deleteMany({'title':'MongoDB 教程'})
db.item_wg.remove({})
db.item_wg.deleteMany({})
// -- mongodb 查询文档 db.collection.find(query, projection)
db.item_wg.find().pretty()
// -- 查用对比条件
// -- 等于 db.item_wg.find({"by":"菜鸟教程"}).pretty()
// -- 小于 db.item_wg.find({"likes":{$lt:50}}).pretty()
// -- 小于等于 db.item_wg.find({"likes":{$lte:50}}).pretty()
// -- 大于 db.item_wg.find({"likes":{$gt:50}}).pretty()
// -- 大于等于 db.item_wg.find({"likes":{$gte:50}}).pretty()
// -- 不等于 db.item_wg.find({"likes":{$ne:50}}).pretty()
// -- 查询and条件
db.item_wg.find({"by":"菜鸟教程", "title":"MongoDB 教程"}).pretty()
// -- 查询or 条件
db.item_wg.find({$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
// -- 查询 and 和or 联合查询 'where likes>50 AND (by = '菜鸟教程' OR title = 'MongoDB 教程')'
db.item_wg.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
// -- 条件操作符的使用
db.item_wg.find({likes: {$gt:50 ,$lte:200}})
// -- mongodb $type 操作符
db.item_wg.insert({
title: 'PHP 教程',
description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['php'],
likes: 200
})
db.item_wg.insert({title: 'Java 教程',
description: 'Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['java'],
likes: 150
})
db.item_wg.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['mongodb'],
likes: 100
})
// -- 想获取 "item_wg" 集合中 title 为 String 的数据,你可以使用以下命令
db.item_wg.find({"title" : {$type : 'string'}})
//-- mongodb limit 与skip 用法,查询定量的数据
db.item_wg.find({},{"title":1,_id:0}).limit(2)
// -- mongodb skip db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
db.item_wg.find({},{"title":1,_id:0}).limit(1).skip(1)
// -- mongodb 排序sort db.COLLECTION_NAME.find().sort({KEY:1}) 1: 升序 -1:降序
db.item_wg.find({},{"title":1,_id:0,"likes":2}).sort({"likes":-1})
// -- mongodb 索引 创建索引 db.collection.createIndex(keys, options) 语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可
db.item_wg.createIndex({"title":1})
// -- mongodb 复合索引
db.item_wg.createIndex({"title":1,"description":-1})
// -- mongodb 后台创建索引
db.item_wg.createIndex({"name":1},{"background":true})
// -- 查看索引集合
db.item_wg.getIndexes()
// -- 查看集合索引大小
db.item_wg.totalIndexSize()
// -- 删除集合所有索引
db.item_wg.dropIndexes()
// -- 删除集合指定索引
db.item_wg.dropIndex("索引名称")
// -- 利用 TTL 集合对存储的数据进行失效时间设置 ,设置在创建记录后,180 秒左右删除
db.col.createIndex({"createDate": 1},{expireAfterSeconds: 180})
// -- mongodb 聚合函数使用 aggregate 类似与count(*) db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
b.item_wg.insert(
{
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
db.item_wg.insert(
{
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
})
db.item_wg.insert(
{
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
})
// -- 通过以上集合计算每个作者所写的文章数,使用aggregate()
// -- 类似 select by_user, count(*) from mycol group by by_user
db.item_wg.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
// -- 插入用户信息
db.user_info.insert(
{
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address": [
{
"building": "22 A, Indiana Apt",
"pincode": 123456,
"city": "Los Angeles",
"state": "California"
},
{
"building": "170 A, Acropolis Apt",
"pincode": 456789,
"city": "Chicago",
"state": "Illinois"
}]
}
)
// -- 查询用户
db.user_info.findOne({"name":"Tom Benzamin"},{"address":1});
// -- 引用关系查询
// >var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
// >var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})
// -- mongodb 覆盖索引查询
db.user_info.insert(
{
"contact": "987654321",
"dob": "01-01-1991",
"gender": "M",
"name": "Tom Benzamin",
"user_name": "tombenzamin"
})
db.user_info.find();
// -- 创建索引
db.user_info.createIndex({gender:1,user_name:1})
// -- 根据索引内存快速查询
db.user_info.find({gender:"M"},{user_name:1,_id:0})
// -- mongodb 查询分析 MongoDB 查询分析常用函数有:explain() 和 hint()
db.user_info.find({gender:"M"},{user_name:1,_id:0}).explain()
// -- 使用hint 查询分析
db.user_info.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()
// -- mongodb 原子操作
db.book_info.insert({
title: "MongoDB: The Definitive Guide",
author: [ "Kristina Chodorow", "Mike Dirolf" ],
published_date: ISODate("2010-09-24"),
pages: 216,
language: "English",
publisher_id: "oreilly",
available: 3,
checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]
})
db.book_info.find();
// -- 使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息
db.book_info.findAndModify ( {
query: {
_id: ObjectId("6406e27979694e763e732f9d"),
available: { $gt: 0 }
},
update: {
$inc: { available: -1 },
$push: { checkout: { by: "abc", date: new Date() } }
}
} )
// -- mongodb 高级索引
db.users.insert(
{
"address": {
"city": "Los Angeles",
"state": "California",
"pincode": "123"
},
"tags": [
"music",
"cricket",
"blogs"
],
"name": "Tom Benzamin"
})
db.users.find({}).pretty()
// -- 基于标签来检索用户,为此我们需要对集合中的数组 tags 建立索引
db.users.createIndex({"tags":1})
// -- 按照索引列检索
db.users.find({tags:"Tom cricket"}).explain()
// -- 索引子文档 需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引
db.users.createIndex({"address.city":1,"address.state":1,"address.pincode":1})
// -- 子文档检索
db.users.find({"address.city":"Los Angeles"}).explain();
db.users.find({"address.state":"California","address.city":"Los Angeles"})
// -- Mongodb Map Reduce
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "mark",
"status":"disabled"
})
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "runoob",
"status":"disabled"
})
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "runoob",
"status":"disabled"
})
db.posts.insert({
"post_text": "菜鸟教程,最全的技术文档。",
"user_name": "runoob",
"status":"active"
})
db.posts.find()
db.posts.mapReduce(
function() { emit(this.user_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"active"},
out:"post_total"
}
)
// -- 查询map Reduce 结果
db.post_total.find()
// -- mongodb 全文检索-- 不支持中文检索
db.posts.insert(
{
"post_text": "enjoy the mongodb articles on Runoob",
"tags": [
"mongodb",
"runoob"
]
})
db.posts.insert(
{
"post_text": "enjoy the mongodb articles on pyhton linux firedway",
"tags": [
"python",
"linux"
]
})
//-- 建立全文索引
db.posts.createIndex({post_text:"text"})
// -- 全文检索
db.posts.find({$text:{$search:"pyhton"}})
// -- mongodb 使用正则表达式
db.posts.find();
db.posts.find({post_text:{$regex:"Runoob"}})
db.posts.find({post_text:/Runoob/})
// -- 不区分大小写的正则表达式
db.posts.find({post_text:{$regex:"runoob",$options:"$i"}})
// -- 数组元素使用正则表达式
db.posts.find({tags:{$regex:"run"}})
// -- mongodb GridFS 添加文件
// -- mongofiles.exe -d gridfs put song.mp3 -d gridfs 指定存储文件的数据库名称,如果不存在该数据库,MongoDB会自动创建。如果不存在该数据库,MongoDB会自动创建。Song.mp3 是音频文件名。
// -- 查看数据库文档 db.fs.files.find()
3.2 相关聚合表达式
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和 | db.mycol.aggregate([{group : {_id : "by_user", num_tutorial : {likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{group : {_id : "by_user", num_tutorial : {likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值 | db.mycol.aggregate([{group : {_id : "by_user", num_tutorial : {likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值 | db.mycol.aggregate([{group : {_id : "by_user", num_tutorial : {likes"}}}]) |
$push | 将值加入一个数组中,不会判断是否有重复的值 | db.mycol.aggregate([{group : {_id : "by_user", url : {url"}}}]) |
$addToSet | 将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入 | db.mycol.aggregate([{group : {_id : "by_user", url : {url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据 | db.mycol.aggregate([{group : {_id : "by_user", first_url : {url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{group : {_id : "by_user", last_url : {url"}}}]) |
3.3 MongoDB 管道
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的
- $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
- match使用MongoDB的标准查询操作。
- $limit:用来限制MongoDB聚合管道返回的文档数。
- $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
- $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
- $group:将集合中的文档分组,可用于统计结果。
- $sort:将输入文档排序后输出。
- $geoNear:输出接近某一地理位置的有序文档。
db.article.aggregate(
{ $project : {
_id : 0 ,
title : 1 ,
author : 1
}});
3.4 Mongodb 原子操作
原子操作常用命令
- $set
用来指定一个键并更新键值,若键不存在并创建。
{ $set : { field : value } }
- $unset
用来删除一个键。
{ $unset : { field : 1} }
- $inc
$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
{ $inc : { field : value } }
- $push
用法:
{ $push : { field : value } }
把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。
- pushAll
同$push,只是一次可以追加多个值到一个数组字段内。
{ $pushAll : { field : value_array } }
- $pull
从数组field内删除一个等于value值。
{ $pull : { field : _value } }
- $addToSet
增加一个值到数组内,而且只有当这个值不在数组内才增加。
- $pop
删除数组的第一个或最后一个元素
{ $pop : { field : 1 } }
- $rename
修改字段名称
{ $rename : { old_field_name : new_field_name } }
- $bit
位操作,integer类型
{$bit : { field : {and : 5}}}
四、MongoDB 复制(副本集) :rescue_worker_helmet:
mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。
mongodb各个节点常见的搭配方式为:一主一从、一主多从。
主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
副本集特征:
- N 个节点的集群
- 任何节点可作为主节点
- 所有写入操作都在主节点上
- 自动故障转移
- 自动恢复
五、 MongoDB Map Reduce 操作:cake:
Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。
MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。
以下是MapReduce的基本语法:
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将 key 与 value 传递给 Reduce 函数进行处理。
Map 函数必须调用 emit(key, value) 返回键值对。
参数说明:
- map :映射函数 (生成键值对序列,作为 reduce 函数参数)。
- reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。
- out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
- query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
- sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
- limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
现在,我们将在 posts 集合中使用 mapReduce 函数来选取已发布的文章(status:"active"),并通过user_name分组,计算每个用户的文章数:
>db.posts.mapReduce(
function() { emit(this.user_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"active"},
out:"post_total"
}
)
以上 mapReduce 输出结果为:
{
"result" : "post_total",
"timeMillis" : 23,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 1,
"output" : 2
},
"ok" : 1
}
结果表明,共有 5 个符合查询条件(status:"active")的文档, 在map函数中生成了 5 个键值对文档,最后使用reduce函数将相同的键值分为 2 组。
具体参数说明:
- result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。
- timeMillis:执行花费的时间,毫秒为单位
- input:满足条件被发送到map函数的文档个数
- emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
- output:结果集合中的文档个数**(count对调试非常有帮助)**
- ok:是否成功,成功为1
- err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大
使用 find 操作符来查看 mapReduce 的查询结果:
> var map=function() { emit(this.user_name,1); }
> var reduce=function(key, values) {return Array.sum(values)}
> var options={query:{status:"active"},out:"post_total"}
> db.posts.mapReduce(map,reduce,options)
{ "result" : "post_total", "ok" : 1 }
> db.post_total.find();
六、SpringBoot 集成MongoDB:school:
6.1 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
6.2 添加配置
spring:
application:
name: boot-mongodb
data:
mongodb:
host: localhost
port: 27017
username: test
password: test
database: info_db
6.3 基于MongoTemplate 开发CRUD
- 创建实体类
@Data
@Document("User")
public class User {
@Id
private String id;
private String name;
private Integer age;
private String email;
private String createDate;
}
- 编写测试类
package com.yongliang.mongodb;
import cn.hutool.json.JSONUtil;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.yongliang.mongodb.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import java.util.List;
import java.util.regex.Pattern;
@SpringBootTest
class BootMongodbApplicationTests {
@Autowired
private MongoTemplate mongoTemplate;
// 插入集合
@Test
void contextLoads() {
User user = new User();
user.setAge(20);
user.setName("test");
user.setEmail("123@qq.com");
User user1 = mongoTemplate.insert(user);
System.out.println(user1);
}
//查询所有记录
@Test
public void findAll() {
List<User> all = mongoTemplate.findAll(User.class);
System.out.println(JSONUtil.toJsonStr(all));
}
//根据id查询
@Test
public void findId() {
User user = mongoTemplate.findById("6406f5de89d50c30e52f6c8b", User.class);
System.out.println(user.toString());
}
//条件查询
@Test
public void findUserList() {
Query query = new Query(Criteria.where("name").is("test").and("age").is(20));
List<User> users = mongoTemplate.find(query, User.class);
System.out.println(JSONUtil.toJsonStr(users));
}
//模糊条件查询
@Test
public void findLikeUserList() {
// name like test
String name = "est";
String regex = String.format("%s%s%s", "^.*", name, ".*$");
/*1、在使用Pattern.compile函数时,可以加入控制正则表达式的匹配行为的参数:
Pattern Pattern.compile(String regex, int flag)
2、regex设置匹配规则
3、Pattern.CASE_INSENSITIVE,这个标志能让表达式忽略大小写进行匹配。*/
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
//创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件)
//构建查询条件
Query query = new Query(Criteria.where("name").regex(pattern));
List<User> users = mongoTemplate.find(query, User.class);
System.out.println(users);
}
//分页查询(带条件)
@Test
public void pageLikeUserList() {
int pageNo = 1;//设置当前页
int pageSize = 3;//设置每页显示的记录数
//条件构建
String name = "est";
String regex = String.format("%s%s%s", "^.*", name, ".*$");
/*1、在使用Pattern.compile函数时,可以加入控制正则表达式的匹配行为的参数:
Pattern Pattern.compile(String regex, int flag)
2、regex设置匹配规则
3、Pattern.CASE_INSENSITIVE,这个标志能让表达式忽略大小写进行匹配。*/
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
//创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件)
//构建查询条件
Query query = new Query(Criteria.where("name").regex(pattern));
//分页构建
//查询数来集合(表)中的总记录数
long count = mongoTemplate.count(query, User.class);
List<User> users = mongoTemplate.find(query.skip((pageNo - 1) * pageSize).limit(pageSize), User.class);
System.out.println(count);
System.out.println(users);
}
//修改操作
@Test
public void updateUser(){
//根据id查询
User user = mongoTemplate.findById("6406f5de89d50c30e52f6c8b", User.class);
//修改值
user.setName("test_02");
user.setAge(2);
user.setEmail("test_02@qq.com");
//调用方法实现修改
Query query = new Query(Criteria.where("_id").is(user.getId()));
Update update = new Update();
update.set("name",user.getName());
update.set("age",user.getAge());
update.set("email",user.getEmail());
//调用mongoTemplate的修改方法实现修改
UpdateResult upsert = mongoTemplate.upsert(query, update, User.class);
long modifiedCount = upsert.getModifiedCount();//获取到修改受影响的行数
System.out.println("受影响的条数:"+modifiedCount);
}
//删除条件
@Test
public void deleteUser(){
Query query = new Query(Criteria.where("_id").is("6406f5de89d50c30e52f6c8b"));
DeleteResult remove = mongoTemplate.remove(query, User.class);
long deletedCount = remove.getDeletedCount();
System.out.println("删除的条数:"+deletedCount);
}
}
6.4 基于MongoRepository开发CRUD
- 添加Repository接口
package com.yongliang.mongodb.repository;
import com.yongliang.mongodb.entity.User;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* @ClassName UserRepository
* @Description: JPA 查询方式
* @Author: zhangyongliang
* @Date: 2023/3/7 16:47
* @Version: V2.3
*/
public interface UserRepository extends MongoRepository<User,String> {
}
- 编写测试类
package com.yongliang.mongodb;
import com.yongliang.mongodb.entity.User;
import com.yongliang.mongodb.repository.UserRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.*;
import java.util.List;
/**
* @ClassName: JpaMongoTest
* @Description:
* @Author: zhangyongliang
* @Date: 2023/3/7 16:48
* @Version: V2.3
*/
@SpringBootTest
public class JpaMongoTest {
@Autowired
private UserRepository userRepository;
//添加操作
@Test
public void save() {
User user = new User();
user.setName("ertong");
user.setAge(20);
user.setEmail("ertong@qq.com");
User user1 = userRepository.save(user);
System.out.println(user1);
}
//查询所有
@Test
public void findAll(){
List<User> lists = userRepository.findAll();
for(User user:lists){
System.out.println(user);
}
}
//根据id查询
@Test
public void findById(){
User user = userRepository.findById("6406fa9b0fe59c4b6c09aa4a").get();
System.out.println(user);
}
//条件查询
@Test
public void findUserList(){
User user = new User();
user.setName("ertong");
user.setAge(20);
Example<User> example = Example.of(user);
List<User> all = userRepository.findAll(example);
System.out.println(all);
}
//模糊条件查询
@Test
public void findLikeUserList(){
///创建匹配器,即如何使用查询条件
ExampleMatcher matcher = ExampleMatcher.matching()//构建对象
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)//改变默认字符串匹配方式:模糊查询
.withIgnoreCase(true);//改变默认大小写忽略方式:忽略大小写
User user = new User();
user.setName("e");
user.setAge(20);
Example<User> example = Example.of(user,matcher);
List<User> all = userRepository.findAll(example);
System.out.println(all);
}
//分页查询
@Test
public void findPageUserAll(){
//设置分页参数
//0代表第一页
Pageable pageable = PageRequest.of(0, 3);
//查询条件
User user = new User();
user.setName("test");
Example<User> userExample = Example.of(user);//查询条件
Page<User> page = userRepository.findAll(userExample, pageable);
System.out.println(page.getContent());
}
//修改操作
@Test
public void updateUser(){
//先根据id出要修改的用户
User user = userRepository.findById("6406f9b94493ab599c5b0db9").get();
//设置修改的值
user.setName("haha");
user.setAge(23);
user.setEmail("hah@qq.com");
User user1 = userRepository.save(user);
System.out.println(user1);
}
//删除
@Test
public void delete(){
userRepository.deleteById("6406f9b94493ab599c5b0db9");
}
}