目录
一、什么是MongoDB?
介绍
- 使用C++编写的具有动态模式的面向文档的NoSQL数据库
- 动态模式支持流畅的多态性
- 将数据存储在类似JSON的文档中(BSON)
- 使用文档(对象)更趋近于许多编程语言
MongoDB中存储的数据类似JSON格式
特点
- 高性能
- 易部署
- 易使用
- 存储数据非常方便
数据模型
- 单个集合中的文档不必具有相同的字段,集合的不同文档的字段的数据类型可能有所不同
最佳实践:一般情况下,集合中的文档具有相似的结构
- 模式验证
创建集合或更改集合时指定JSON模式,模式验证发生在插入和更新期间,已经存在的文档不接受验证检查,直到被修改
- 上限集合
固定大小的集合, 集合填满分配的空间后,通过覆盖集合中最旧的文档来存放新文档
副本集
MongoDB复制是将数据同步在多个服务器的过程。
- 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。
- 如果当前的主实例失败,会在副本集中选出一个新的主实例
MongoDB的复制至少需要两个节点
- 其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。
- 各个节点常见的搭配方式为:一主一从、一主多从
二、MongoDB安装
配置yum源
- 新建配置文件:
vi /etc/yum.repos.d/mongodb.repo
#写入以下配置信息
[MongoDB]
name=MongoDB Repository
baseurl=http://mirrors.aliyun.com/mongodb/yum/redhat/7Server/mongodb-org/4.0/x86_64/
gpgcheck=0
enabled=1
下载
- 下载命令:
yum install mongodb-org
启动
- 启动命令:
sudo systemctl start mongod.service
如果是root用户下,前面可以不加sudo
三、MongoDB基本命令
- 启动client:
mongo
- 查看版本:
mongod --version
DataBase
- 创建库:
use [库名]
use 库名,如果存在就进入此数据库,如果不存在就创建
注意:使用命令use命令创建数据库后,并没有真正生成对应的数据文件,如果此时退出,此数据库将被删除,只有在此数据库中创建集合后,才会真正生成数据文件
- 删除当前数据库:
db.dropDatabase()
- 查看所有数据库:
show dbs
Collection
Collection属于DataBase的下一级,可以成为Table也可以成为集合,Collection下的每条数据为一个文档
- 创建集合:
#显式创建
db.createCollection("集合名称")
#隐式创建
#创建集合并同时向集合中插入数据
db.集合名称.insert({
"name":"zhangshang","age":20})
- 查询:
#查看当前数据库中所有的集合
#方式一:
show collections
#方式二:
show tables
Document
Document就是Collection的下一级,每条数据为一个文档也就是一个Document
- 单条插入
#将一条记录插入到collection表中,会自动添加_id字段,并分配_id字段的值
db.events.insert({
"name":"demo record"}) #不推荐
db.events.insertOne({
"name":"demo record"})
- 批量插入
db.inventory.insertMany([
{
item: "journal", qty: 25, status: "A", size: {
h: 14, w: 21, uom: "cm" }, tags: [ "blank", "red" ] },
{
item: "notebook", qty: 50, status: "A", size: {
h: 8.5, w: 11, uom: "in" }, tags: [ "red", "blank" ] },
{
item: "paper", qty: 100, status: "D", size: {
h: 8.5, w: 11, uom: "in" }, tags: [ "blank", "plain" ] },
{
item: "planner", qty: 75, status: "D", size: {
h: 22.85, w: 30, uom: "cm" }, tags: [ "blank" ] },
{
item: "postcard", qty: 45, status: "A", size: {
h: 10, w: 15.25, uom: "cm" }, tags: [ "blue" ] }
]);
-
查询所有文档:
db.集合名称.find()
-
条件查询:
db.集合名称.find({条件})
#常用条件匹配
$lt 表示的是小于
db.customers.find({
age:{
$lt:102}})
$lte 表示的小于或等于
db.customers.find({
age:{
$lte:102}})
$gt 表示的是大于
db.customers.find({
age:{
$gt:109}})
$gte 表示的是大于或等于
db.customers.find({
age:{
$gte:109}})
$ne 表示不等于。单独使用$ne,它也不会利用索引的优势,反而会进行全表扫描。
db.customers.find({
id:{
$ne:1}})
$in 表示返回 key 的值在某些 value 范围内
db.customers.find({
id:{
$in:[1,2]}})
$nin 表示返回 key 的值不在某些 value 范围内,$nin 是一种比较低效的査询选择器,它会进行全表扫描,因此最好不要单独使用$nin
db.customers.find({
id:{
$nin:[1,2]}})
$or 表示或运算的选择器,主要用于对两个不同 key 对应的文档进行连接。
db.customers.find({
$or:[{
id:11},{
age:119}]
$and 表示与运算的选择器,对于两个不同的 key,要同时满足条件。
db.customers.find({
$and:[{
id:11},{
age:111}]})
#---------------------------------------示例-------------------------------------------------
#匹配指定字段值:
db.inventory.find({
status: "D" })
#过滤查询,设定取值范围:
db.inventory.find( {
status: {
$in: [ "A", "D" ] } } )
#范围选择器
# 表示的是小于 120,大于或等于 119
db.customers.find({
age:{
$lt:120,$gte:119}})
- 格式化输出:
db.集合名称.find().pretty()
#标准查询
> db.persons.find()
{
"_id" : 1, "name" : "zhangsan", "age" : 20, "work" : {
"title" : "beijing", "hours" : 10 } }
#格式化后输出,类似json样式输出
> db.persons.find().pretty()
{
"_id" : 1,
"name" : "zhangsan",
"age" : 20,
"work" : {
"title" : "beijing",
"hours" : 10
}
}
- 投影查询:MongoDB支持返回某些特定的字段值
#语法
#其中1表示显示该字段,0表示不显示
db.集合名称.find({
条件},{
字段:1})
# -------------------------------------示例--------------------------------------------------
# 查询文档中status=D的文档,只返回文档中status和size两个字段的值
db.inventory.find({
status: "D" },{
status:1,size:1})
# 查询文档中status=D的文档,返回除了size字段的所有字段
db.inventory.find({
status: "D" },{
size:0})
- 更新操作:update
# 语法
db.collection.update( <query>, <update>, {
upsert: <boolean>,multi: <boolean>,writeConcern: <document>})
# 示例
# 这个操作将更改集合中与name: "apple"匹配的第一个文档,使用$set将其中的字段name设为"apple5s",使用$inc将字段price增加4000,其他字段保持不变。
db.goods.update({
name: "apple"},{
$set: {
name: "appleSs"},$inc: {
price:4000}})
# updateOne和updateMany操作
# 1.按条件更新数据,只更新查询排在第一位的数据,将值为item的字段,改为journal
db.inventory.updateOne({
status : "D" },{
$set: {
item : "journal"} },{
upsert: true });
# 2.更新满足条件的全部数据
db.inventory.updateMany({
qty : {
$gt: 75 } },{
$set: {
status: "A" } });
- 删除操作:remove、delete
#使用remove删除
db.col.remove({
title:'MongoDB 教程'})
# remove已经过时,官方推荐使用下面的方式:
# 删除集合下全部文档:
db.inventory.deleteMany({
})
# 删除满足条件的全部文档:
db.inventory.deleteMany({
status : "A" })
# 删除一个文档:
db.inventory.deleteOne( {
status: "D" } )
- Bulk-Write:需要批量操作时候,可以使用 bulk_write,节省网络连接交互次数
# 示例
db.characters.bulkWrite([
{
insertOne : {
"document" : {
"_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4 } } },
{
insertOne : {
"document" : {
"_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3 } } },
{
updateOne : {
"filter" : {
"char" : "Eldon" },
"update" : {
$set : {
"status" : "Critical Injury" } }
}
},
{
deleteOne : {
"filter" : {
"char" : "Brisbane"} } }
],{
ordered : false } );
索引
MongoDB的索引是Collection级别的
- MongoDB索引的数据结构是B+树
- MongoDB默认为所有集合都创建了一个_id字段的单字段索引,而且这个索引是唯一的,不能被删除
- 多键索引–索引存储在数组中的内容
- 文本索引–为文本搜索索引字符串的内容
- 哈希索引–索引字段的哈希值
# 语法
db.collection.createIndex(keys, options)
# 语法中 Key 值为你要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为 -1即可
# 示例
db.myColl.createIndex( {
“score”: 1, “price”: 1, “category”: -1 })
四、聚集分析
MongoDB主要提供了三种对数据进行分析计算的方式
- 管道模式聚集分析
- MapReduce聚集分析
- 简单函数和命令的聚集分析
管道模式聚集分析
管道类似于UNIX上的管道命令。数据通过一个多步骤的管道,每个步骤都会对数据进行处理,最后返回需要的结果集
MapReduce聚集分析
MongoDB也提供了当前流行的MapReduce的并行编程模型,为海量数据的查询分析提供了一种更加高效的方法
- map阶段:处理每个文档并为每个文档发出一个或多个对象输入文件
- reduce阶段:聚合map阶段的输出
简单聚集函数
管道模式和MapReduce模式基本上可以解决数据分析中的所有问题,但有时在数据量不是很大的情况下,直接调用基于集合的函数会更简单
- distinct
- count
五、读/写关注
写关注(Write Concern)
- Write Concern,简称MongoDB写入安全机制
- 是一种客户端设置,用于控制写入安全的级别。
- 描述了MongoDB写入到mongod单实例,副本集,以及分片集群时何时应答给客户端。
- 写关注用法
# 参数:
{
w: <value>, j: <boolean>, wtimeout: <number> }
# 示例:
db.blogs.insert({
name:"kgc"},{
writeConcern:{
w:0}})
读关注( Read Concern)
读关注允许控制从副本集和副本集分片读取数据的一致性和隔离性的属性
读关注级别
- local/available:查询返回实例的数据,没有确保数据已写入大多数副本集成员(即可能会回滚)
- majority:只要是在发起读操作之前,已经大部分节点ACK的数据,都可以被读取
- linearizable:该查询能返回的数据是在读操作开始之前完成的所有成功的多数已确认的写操作
- snapshot:仅适用于多文档的事务操作
加载CSV文件到MongoDB
- 下载mongoimport:
sudo yum install mongodb-org-tools-4.0.1
- 导入:
mongoimport --headerline --type=csv --file=./events.csv -d events_db -c events
Java操作MongoDB
import com.mongodb.client.*;
import com.mongodb.*;
import java.util.Map;
public class mug1 {
public static void main(String[] args) {
try {
MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("mug”);
MongoCollection coll = db.getCollection("foo");
MongoCursor c = coll.find().iterator();
while(c.hasNext()) {
Map doc = (Map) c.next();
System.out.println(doc);
}
} catch(Exception e) {
// ... }
}
}
MongoDB与Hive整合
使用MongoStorageHandler操作基于MongoDB的Hive表,需要提前拷贝相应Jar包
- 拷贝Jar到HIve的Lib目录下
mongo-hadoop-core-2.0.2.jar
mongo-hadoop-hive-2.0.2.jar
mongo-java-driver-3.2.1.jar
- 在Hive中创建表,关联mongoDB
create table individuals(
id int,
name string,
age int,
work struct<title:string,hours:int>
)
stored by "com.mongodb.hadoop.hive.MongoStorageHandler"
with serdeproperties('mongo.columns.mapping'='{"id":"_id"}')
tblproperties('mongo.uri'='mongodb://127.0.0.1:27017/test.persons');
#如果是内部表,在删除表的时候也会删除mongodb里面的数据。
#mongo.columns.mapping:hive表与mongodb字段的映射,字段名完全相同,可以不写,如果需要修改对应的字段可以指定出来
#就像这样with serdeproperties('mongo.columns.mapping'='{"id":"_id","work.title":"job.postition"}')
- 插入数据
insert into individuals select 1,"zhangsan",20,named_struct('title','beijing','hours',10);
- 查看mongoDB中的数据
#查看集合
> show tables;
persons
#查看persons中的数据
> db.persons.find()
{ "_id" : 1, "name" : "zhangsan", "age" : 20, "job" : { "postition" : "beijing", "hours" : 10 } }
#可以看到在hive中创建的映射表插入数据后,在mongoDB中也可以查询出来
MongoDB与Spark整合
Spark操作MongoDB中的Collection
import com.mongodb.spark._
val spark = SparkSession.builder().master("local")
.config("spark.mongodb.input.uri", "mongodb://127.0.0.1/")
.config("spark.mongodb.input.collection", "restaurants")
.config("spark.mongodb.output.uri", "mongodb://127.0.0.1/")
.config("spark.mongodb.output.collection", "restaurants")
.getOrCreate()
//读
val df = MongoSpark.load(spark)
//写
MongoSpark.save(df.write.mode("overwrite"))
MongoDB认证
- 启动mongo client创建用户,设置密码
#语法
db.createUser
- 关闭MongoDB服务
- 将/etc/mongod.conf中authorization设置为enable:
vi /etc/mongod.conf
security:
authorization: enabled
- 重启服务,并使用用户密码登录
mongo --port 27017 -u "kgc" -p "password" --authenticationDatabase "admin"