Mongo基础

一、MongoDB中的基本概念和原理

1、MongoDB介绍及概念

  MongoDB是一个基于【分布式文件存储】的数据库,它属于NoSql数据库,由C++编写

  NoSql可以分为键值型(K-V)和文档型(Document)两类,其中MongoDB就属于文档型NoSql,他文档中是以类似Json的Bson格式进行存储。

  同时MongoDB还是一个介于非关系型数据库和关系型数据库之间的产品,是非关系型数据库中功能最丰富,最想关系型数据库的,它支持的数据结构非常松散,是类似Json的Bson,因此可以存储比较复杂的数据类型。

  MongoDB最大的特点就是它支持的查询语言非常强大,其语法优点类似于面向对象的查询语言,几乎可以实现类似关系型数据库单表查询的绝大部分功能,而且还支持对数据库建立索引。

  对于MongoDB中的概念,结合MySql进行对比

MySql术语 MongoDB术语 解释说明
database database 数据库
table collection 表/集合
row document 行/文档
column field 列/域
index index 索引
table joins   表连接/MongoDB不支持
primary key primary key 主键(MongoDB自动将_id字段设置为主键)

(1)数据库database

  一个MongoDB中可以建立多个数据库;MongoDB的默认数据库为“db”,该数据库存储在data目录中;MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

  有一些数据库名是保留的,可以直接访问这些特殊作用的数据库。

  admin:从权限角度来看,这是一个root级别的数据库,要是将一个用户添加到这个数据库,这个用户自动继承所有的数据库权限,一些特定的服务端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器

  local:这个数据库永远不会被复制,可以用来存储仅限于本地单台服务器的任意集合

  config:当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息

(2)集合Collection

  集合就是MongoDB中的文档组,类似于关系型数据库的表,集合没有特定的结构,这意味着我们可以插入不同格式和不同类型的数据,但通常情况下,我们插入集合的数据都会有一定的关联性。

  集合的命名规则:

    集合中不能有空字符串;

    集合不能含有\0,\0结表示集合名称的结尾;

    集合不能以“system.”开头,这是为系统集合保留的前缀;

    用户创建集合名字不能含有保留字符,有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的结合中包含了该字符串,除非要访问这种系统创建的集合,否则千万不要在名字里出现$。

  capped collections

  capped collections就是固定大小的collection,他有很高的性能以及队列过期的特性(过期按照插入的顺序),Capped collection是高性能的自动维护对象的插入顺序,它非常适合类似记录日志的功能,和标准的collection不同,我们必须显式的创建一个capped collection,并且指定其大小,单位是字节。collection的数据存储空间是提前分配的。

  capped collections可以按照文档的插入顺序保存到集合中,而且这些文档在磁盘上存放的文职也是按照插入顺序来保存的,所以当我们更新capped collections中的文档时,更新后的文档不可以超过更新前的文档大小,这样的话就可以确保所有文档在磁盘上的位置一直保持不变。

  由于capped collection是按照文档的插入顺序而不是使用索引来确定插入位置,这样的话可以提高添加数据的效率,MongoDB的操作日志文件oplog.rs就是利用Capped collections来实现的。

  在capped collections中,我们可以添加新的对象,也可以更新对象,由于其空间是提前分配的,所以无论是新增还是更新,都不会增加存储空间,如果更新后空间需要增加,则更新会失败;

  使用capped collections不能删除一个文档,但是可以使用drop()方法删除collections所有的行,删除之后,我们必须显式的重新创建这个collection。

(3)文档Document

  文档是一组键值对(Bson),MongoDB不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是MongoDB很大的特点。

  需要注意的是,文档的键值对是有序的;文档中的值不仅可以是在双引号中的字符串,同时还可以是其他集中数据类型(甚至可以是整个嵌入的文档);MongoDB区分数据类型和大小写;和关系型数据库一样,MongoDB不能有重复的键;除了极少数情况,键可以是任意的UTF-8字符。

  文档中键的命名规范:键不能含有'\0',这个字符串是用来表示键的结尾; 点和美元符号(.和$)有特别的含义,只有在特定环境下才能使用;以下划线('_')开头的键是保留的,但是不严格要求。

(4)元数据

  数据库的信息是存储在集合中,他们使用了系统的命名空间(以dbname.system开头)。

  在MongoDB数据库中名字空间 .syatem.* 是包含多种系统信息的特殊集合,例如:

集合命名空间 描述
dbname.system.namespaces 列出所有名字空间
dbname.system.indexs 列出所有索引
dbname.system.profile 包含数据库概要信息
dbname.system.users 列出所有可以访问数据库的用户
dbname.system.sources 包含赋值对端(slave)的服务器信息和状态

  对于修改系统集合中的对象有如下限制:

    在system.indexs中插入数据,可以创建索引,但除此之外,表信息是不可变的。

    system.users是可修改的,system.profile是可删除的。

2、MongoDB数据类型

  下表为MongoDB中常用的几种数据类型

数据类型 说明 解释 举例
String 字符串 UTR-8编码的字符串才是合法的 {"name":"lcl"}
Integer 整型数值  

{"age":18}

Boolean 布尔类型   {"man":true}
Double 双精度浮点类型   {"v":13.14}
Array 数组   {"arr":["lcl","qmm"]}
Timestamp 时间戳    
ObjectID 对象ID 用于创建文档的ID {"_id":ObjectId("123")}
Null 空值   {"v":null}
Date 日期   {"v":new Date()}
Regular 正则表达式 文档中可以包含正则表达式,遵循JS语法 {"v":/demo/query}
Code 代码 可以包含js代码 {"v":function()}
File 文件 二进制转码(Base64)后存储(文件<16M);GridFS(文件>16M) GridFS用两个集合来存储一个文件:fs.files与fs.chunks

  这里特殊说明以下ObjectID,其类似于唯一主键,可以快速的生成和排序,包含12bytes,其中前4个字节表示时间戳,接下来的3个字节是机器的识别码,再接着的两个字节是由进程id组成的PID,最后三个字节是随机数。

  MongoDB中存储的文档必须有一个_id键,这个键的值可以是任何类型的,默认是个ObjectId对象,同时由于ObjectId中保存了创建的时间戳,所以不需要为文档保存时间戳字段,可以直接使用getTimestamp函数来获取文档的创建时间。

3、图解MongoDB底层原理

  MongoDB的部署方案有单机部署、主从部署、副本集(主备)部署、分片部署、副本集与分片混合部署这几种部署方案。

(1)副本集集群:

  对于副本集集群,又有主从两种角色,写数据只能通过主节点,然后通过异步的方式将数据同步到从节点;查询则可以从主从里面的任意节点进行查询。

(2)副本集与分片混合部署:

  MongDB的集群部署方案有三种角色:实际数据存储节点、配置文件存储节点、路由接入节点

  实际数据存储节点:作用就是存储数据

  配置文件存储节点:作用存储的是分片键与chunk的关系以及chunk与server的关系

  路由接入节点:作用就是在分片的情况下起到负载均衡的作用

  MongoDB的客户端直接与路由节点连接,然后从配置节点上查询数据,根据查询结果到实际的数据存储节点上查询和存储数据。

  相同的副本集中的节点存储的数据是相同的,副本集中的节点分为主节点、从节点和仲裁节点(非必须),类似于redis的主从+哨兵模式。这样是为了解决高性能、高可用、数据备份

  不同的副本集中存储的数据不同,这种设计是为了高扩展。

4、MongoDB的应用场景和不适用场景

(1)适用场景

  更高的写入负载:MongoDB更侧重大数据量的写入性能,所以MongoDB非常适合存储“低价值”的数据。

  高可用性:MongoDB的主从配置非常简单,并且MongoDB可以快速的处理单点故障,自动、安全的完成故障转移。

  数据量很大或者未来会很大,或者表结构不明确:如果使用Mysql这类的关系型数据库,数据扩展是比较困难的,特别是当数据量大的时候去变更数据结构,非常的困难;在Mysql中,当一个单表数据量达到1000W或者达到5-10G的时候,会出现明显的性能下降,此时就需要进行分库分表等操作来进行垂直和水平扩展,并且这些扩展是需要借助驱动层或代理层来完成这类的需求,但是MongoDB内建了多种数据分片的特性,可以很好的适应大数据量的需求。

  基于位置的数据查询:MongoDB支持二维空间索引,因此可以快速精确的从指定位置获取数据。

(2)不适用场景

  在某些场景下,MongoDB作为一个非关系型数据库有其局限性,MongoDB不支持事务操作,所以需要用到事务的地方不建议使用MongoDB,另外MongoDB不支持join操作,需要复杂查询的应用也不建议使用MongoDB。

二、MongoDB的安装

1、安装与启动

  (1)下载&解压&重命名

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.11.tgz
tar -zxvf mongodb-linux-x86_64-rhel70-3.6.11.tgz
mv mongodb-linux-x86_64-rhel70-3.6.11 mongo-3.6.11

 

   (2)配置环境变量

vim /etc/profile
source /etc/profile

  profile文件新增mongo配置

export PATH=$JAVA_HOME/bin:/root/rj/mongo/standalone/mongo-3.6.11/bin:$PATH

  (3)创建mongo配置文件

mkdir data logs etc
vim etc/mongodb.cfg

  mongodb.cfg文件内容

#数据库文件位置
dbpath=/root/rj/mongo/standalone/mongo-3.6.11/data

#日志文件位置
logpath=/root/rj/mongo/standalone/mongo-3.6.11/logs/mongodb.log

#以追加方式写入日志
logappend=true

#是否以守护进程方式运行
fork=true

#绑定客户端访问的ip 0.0.0.0 不绑定ip
bind_ip=0.0.0.0

#端口
port=27017

  (4)启动

./bin/mongod --config etc/mongodb.cfg

2、连接客户端与常用客户端

  客户端连接:

./bin/mongo

  常用的客户端:

    Navicat for mongodb

    MongoVUE

    Studio 3T

    Robo 3T

    RockMongo

三、常用命令

1、数据库相关命令  

  创建数据库:use dbName

> use lcldb
switched to db lcldb

  查询所有数据库:show dbs

  可以发现下面的命令结果并没有刚才创建的数据库,因为数据库中需要有值才会显示数据库

> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

  插入数据:db.collectionName.insert()

  可以看到,插入数据后,重新查看数据库,就有该数据库

> db.lclconllection.insert({"name":"lcl","age":18})
WriteResult({ "nInserted" : 1 })
> show dbs
admin   0.000GB
config  0.000GB
lcldb   0.000GB
local   0.000GB

  删除数据库:db.dropDatabase()

> db.dropDatabase()
{ "dropped" : "lcldb", "ok" : 1 }
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

2、集合相关命令  

  创建集合:db.createCollection(name,options)

  name是集合的名称,options可选参数,指定有关内存大小及索引的选项

  options可以是以下参数:

字段 类型 描述
capped boolean (可选)如果为true,则创建固定大小的集合,当达到最大值时,将会覆盖最早的文档,当该值为true时,必须指定size大小
autoIndex boolean (可选)如果为true,自动在_id字段创建索引,默认为false
size int (可选)为固定集合制定一个最大值(以字节计),如果capped为true,也需要指定该字段
max int (可选)指定固定集合中包含文档的最大数量

  在插入文档时,MongoDB首先检查固定集合的size字段,然后检查max字段。

> db.createCollection("lcltest")
{ "ok" : 1 }
> show collections
lcltest

  删除集合:db.collectionName.drop()

> db.lcltest.drop()
true
> show collections

3、文档相关命令  

  插入文档:db.collectionName.insert(document)

> db.test.insert({"name":"lcl","age":18})
WriteResult({ "nInserted" : 1 })
> db.test.insert({"name":"qmm","age":18})
WriteResult({ "nInserted" : 1 })

  查询文档:db.collection.find(query,projection)

  query:(可选)使用查询操作符指定查询条件

  projection:(可选)是用投影操作符指定返回的键,查询时返回文档中所有的键值,只需省略该参数即可(默认省略)

  如果需要以易懂的方式来读取数据,可以使用pretty()方法,语法:db.collection.find().pretty()

> db.test.find()
{ "_id" : ObjectId("601c0e692f8c31e7c01fdd2e"), "name" : "lcl", "age" : 18 }
{ "_id" : ObjectId("601c0e9b2f8c31e7c01fdd2f"), "name" : "qmm", "age" : 18 }
{ "_id" : ObjectId("601c10142f8c31e7c01fdd30"), "name" : "lcl", "age" : 22 }
{ "_id" : ObjectId("601c10172f8c31e7c01fdd31"), "name" : "lcl", "age" : 33 }

  删除文档:db.collection.remove(<query>,<justOne>)

  如果是2.6之后的版本,语法:db.collection.remove(<query>,{justOne:boolean,writeConcern:<document>})

  query:(可选)删除文档的条件

  justOne:(可选)如果设置为true或1,则只删除一个文档,如果不设置该参数,或使用默认值false,则删除所有匹配条件的文档。

  writeConcern:(可选)抛出异常级别

> db.test.remove({"name":"lcl"})
WriteResult({ "nRemoved" : 3 })
> db.test.find()
{ "_id" : ObjectId("601c0e9b2f8c31e7c01fdd2f"), "name" : "qmm", "age" : 18 }
> db.test.remove({'name':'lcl'},1)
WriteResult({ "nRemoved" : 1 })
> db.test.find()
{ "_id" : ObjectId("601c0e9b2f8c31e7c01fdd2f"), "name" : "qmm", "age" : 18 }
{ "_id" : ObjectId("601c11022f8c31e7c01fdd33"), "name" : "lcl", "age" : 33 }

  limit与skip:limit是限定查询条数,skip是跳过指定的数据

> db.createCollection('lcltest')
{ "ok" : 1 }
> db.lcltest.insert({"title":"test","id":1})
WriteResult({ "nInserted" : 1 })
> db.lcltest.insert({"title":"test","id":2})
WriteResult({ "nInserted" : 1 })
> db.lcltest.insert({"title":"test","id":3})
WriteResult({ "nInserted" : 1 })
> db.lcltest.insert({"title":"test","id":4})
WriteResult({ "nInserted" : 1 })
> db.lcltest.insert({"title":"test","id":5})
WriteResult({ "nInserted" : 1 })
> db.lcltest.insert({"title":"test","id":6})
WriteResult({ "nInserted" : 1 })
> db.lcltest.find().limit(3)
{ "_id" : ObjectId("601c1a2c2f8c31e7c01fdd34"), "title" : "test", "id" : 1 }
{ "_id" : ObjectId("601c1a2f2f8c31e7c01fdd35"), "title" : "test", "id" : 2 }
{ "_id" : ObjectId("601c1a312f8c31e7c01fdd36"), "title" : "test", "id" : 3 }
> db.lcltest.find().skip(3)
{ "_id" : ObjectId("601c1a332f8c31e7c01fdd37"), "title" : "test", "id" : 4 }
{ "_id" : ObjectId("601c1a362f8c31e7c01fdd38"), "title" : "test", "id" : 5 }
{ "_id" : ObjectId("601c1a382f8c31e7c01fdd39"), "title" : "test", "id" : 6 }

  文档排序:db.collectionName.find().sort(keys,options)

  在MongoDB中使用sort()对文档进行排序,在该方法中可以指定排序的字段,并可以使用1或者-1表示升序或者降序,其中1表示升序,-1表示降序。

> db.lcltest1.find().sort({"name":1})
{ "_id" : ObjectId("601c1b53203f9cdfbf50b273"), "title" : "test", "name" : 16, "id" : 8 }
{ "_id" : ObjectId("601c1b45203f9cdfbf50b271"), "title" : "test", "name" : 18, "id" : 5 }
{ "_id" : ObjectId("601c1b4c203f9cdfbf50b272"), "title" : "test", "name" : 25, "id" : 3 }

4、索引相关命令  

  MongoDB索引:db.collectionName.createIndex(keys,options)

  key为创建索引的字段,options为1表示按照升序创建索引,为-1表示按照降序创建索引,同时也可以设置多个字段索引。

> db.lcltest1.createIndex("name")
{
        "ok" : 0,
        "errmsg" : "The field 'key' must be an object, but got string",
        "code" : 14,
        "codeName" : "TypeMismatch"
}
> db.lcltest1.createIndex({"title":1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.lcltest1.createIndex({"title":1,"id":-1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "ok" : 1
}

  对于createIndex()方法的可选接收参数,列表如下:

可选参数 类型 描述
background boolean 创建索引过程中会阻塞其他数据库操作,background可指定以后后台方式创建索引,即增加background可选参数,默认为false
unique boolean 是否为唯一索引,默认为false
name String 索引名称,如果未指定,MongoDB会通过连接索引的字段名和排序顺序胜场一个索引名称
dropDups boolean 3.0之后版本已废弃,在建立唯一索引时是否删除重复的记录,指定true创建唯一索引,默认为false
sparse boolean 对文档中不存在的字段数据是否启用索引,这个参数要特别注意,如果设置为true的话,在索引字段中不会查出不包括该字段的文档,默认为false
expireAfterSeconds integer 指定一个以秒为单位的数值,完成TTL设定,设定集合的生存时间
v index version 索引版本号,默认的索引版本取决于mongodb创建索引时运行的版本
weights document 索引权重值,数值在1-99999之间,表示该索引相对于其他索引字段的权重得分
default_language string 对于文本索引,该参数决定了停用词以及词干和词器的规则列表,默认为英语
language_override string 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为language

> db.lcltest1.createIndex({"title":1,"id":-1,"name":1},{background:true}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 3, "numIndexesAfter" : 4, "ok" : 1 }

  查询集合索引:db.collectionName.getIndexes()

> db.lcltest1.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "lcldb.lcltest1"
        },
        {
                "v" : 2,
                "key" : {
                        "title" : 1
                },
                "name" : "title_1",
                "ns" : "lcldb.lcltest1"
        },
        {
                "v" : 2,
                "key" : {
                        "title" : 1,
                        "id" : -1
                },
                "name" : "title_1_id_-1",
                "ns" : "lcldb.lcltest1"
        },
        {
                "v" : 2,
                "key" : {
                        "title" : 1,
                        "id" : -1,
                        "name" : 1
                },
                "name" : "title_1_id_-1_name_1",
                "ns" : "lcldb.lcltest1",
                "background" : true
        }
]

  查看集合索引大小:db.collectionName.totalIndexSize()

> db.lcltest1.totalIndexSize()
65536

  删除指定索引:db.collectionName.dropIndex(indexName)

> db.lcltest1.dropIndex("title_1")
{ "nIndexesWas" : 4, "ok" : 1 }

  删除所有索引:db.collectionName.dropIndexes()

> db.lcltest1.dropIndexes()
{
        "nIndexesWas" : 3,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : 1
}

5、聚合查询相关命令  

  数据准备:

> db.lcltest2.find()
{ "_id" : ObjectId("601c258a59d44de38d3b4385"), "city" : "BJ", "name" : "kcl1", "age" : 15 }
{ "_id" : ObjectId("601c259259d44de38d3b4386"), "city" : "BJ", "name" : "kcl2", "age" : 17 }
{ "_id" : ObjectId("601c259459d44de38d3b4387"), "city" : "BJ", "name" : "kcl2", "age" : 19 }
{ "_id" : ObjectId("601c25a059d44de38d3b4388"), "city" : "BJ", "name" : "kcl4", "age" : 34 }
{ "_id" : ObjectId("601c25a359d44de38d3b4389"), "city" : "BJ", "name" : "kcl5", "age" : 34 }
{ "_id" : ObjectId("601c25b559d44de38d3b438a"), "city" : "SH", "name" : "lcl1", "age" : 31 }
{ "_id" : ObjectId("601c25bc59d44de38d3b438b"), "city" : "SH", "name" : "lcl2", "age" : 23 }
{ "_id" : ObjectId("601c25c259d44de38d3b438c"), "city" : "SH", "name" : "lcl3", "age" : 18 }

  group聚合:db.collections.aggregate([{$group:{_id:$oldField,newField2:{function:oldField2}}])

  解释以下上面的表达式,db.collections.aggregate([{$group: {_id  这些是固定的,表示要使用聚合查询相关的命令,其中_id是必须写,并且值表示使用哪个字段进行聚合,newField表示聚合查询后得到的列,而oldField表示原collection中的列,需要使用$进行获取对应的值。

  下面的所有命令都是按照上面的表达式进行处理的。

  $sum求和:

> db.lcltest2.aggregate([{$group:{_id:"$city",sum123:{$sum:"$age"}}}])
{ "_id" : "SH", "sum123" : 72 }
{ "_id" : "BJ", "sum123" : 119 }

  $avg求平均值:

> db.lcltest2.aggregate([{$group:{_id:"$city",sum123:{$avg:"$age"}}}])
{ "_id" : "SH", "sum123" : 24 }
{ "_id" : "BJ", "sum123" : 23.8 }

  $min求最小值

> db.lcltest2.aggregate([{$group:{_id:"$city",sum123:{$min:"$age"}}}])
{ "_id" : "SH", "sum123" : 18 }
{ "_id" : "BJ", "sum123" : 15 }

  $max求最大值

> db.lcltest2.aggregate([{$group:{_id:"$city",sum123:{$max:"$age"}}}])
{ "_id" : "SH", "sum123" : 31 }
{ "_id" : "BJ", "sum123" : 34 }

  $match取值后分组

  例如获取每个城市年龄在19-40之间的人数

> db.lcltest2.aggregate([{$match:{age:{$gt:19,$lte:40}}},{$group:{_id:"$city",count123:{$sum:1}}}])
{ "_id" : "SH", "count123" : 2 }
{ "_id" : "BJ", "count123" : 2 }

  $sort按照指定列排序

> db.lcltest2.aggregate([{$sort:{age:-1}}])
{ "_id" : ObjectId("601c25a059d44de38d3b4388"), "city" : "BJ", "name" : "kcl4", "age" : 34 }
{ "_id" : ObjectId("601c25a359d44de38d3b4389"), "city" : "BJ", "name" : "kcl5", "age" : 34 }
{ "_id" : ObjectId("601c25b559d44de38d3b438a"), "city" : "SH", "name" : "lcl1", "age" : 31 }
{ "_id" : ObjectId("601c25bc59d44de38d3b438b"), "city" : "SH", "name" : "lcl2", "age" : 23 }
{ "_id" : ObjectId("601c259459d44de38d3b4387"), "city" : "BJ", "name" : "kcl2", "age" : 19 }
{ "_id" : ObjectId("601c25c259d44de38d3b438c"), "city" : "SH", "name" : "lcl3", "age" : 18 }
{ "_id" : ObjectId("601c259259d44de38d3b4386"), "city" : "BJ", "name" : "kcl2", "age" : 17 }
{ "_id" : ObjectId("601c258a59d44de38d3b4385"), "city" : "BJ", "name" : "kcl1", "age" : 15 }

  $limit获取前指定条数数据

> db.lcltest2.aggregate([{$limit:3}])
{ "_id" : ObjectId("601c258a59d44de38d3b4385"), "city" : "BJ", "name" : "kcl1", "age" : 15 }
{ "_id" : ObjectId("601c259259d44de38d3b4386"), "city" : "BJ", "name" : "kcl2", "age" : 17 }
{ "_id" : ObjectId("601c259459d44de38d3b4387"), "city" : "BJ", "name" : "kcl2", "age" : 19 }

  $project设置显示或不显示哪些字段,显示用1表示,不显示用0表示

> db.lcltest2.aggregate([{$project:{_id:0,city:1,name:1}}])
{ "city" : "BJ", "name" : "kcl1" }
{ "city" : "BJ", "name" : "kcl2" }
{ "city" : "BJ", "name" : "kcl2" }
{ "city" : "BJ", "name" : "kcl4" }
{ "city" : "BJ", "name" : "kcl5" }
{ "city" : "SH", "name" : "lcl1" }
{ "city" : "SH", "name" : "lcl2" }
{ "city" : "SH", "name" : "lcl3" }

  $lookup用于多文档关联,类似于sql的多表关联

 

三、MongoDB的JAVA客户端

1、mongodb-java-api(基本上不使用)

  由于现在基本上不用了,直接贴出代码

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.18</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>3.10.1</version>
        </dependency>

        <!-- 单元测试Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
@SpringBootTest
@Slf4j
class LclGalaxyMongoApplicationTests {

    @Test
    void contextLoads() {
    }


    private MongoClient client;

    @Before
    public void init(){
        client = new MongoClient("127.0.0.1",27017);
    }

    @Test
    public void createConnection(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        mongoDatabase.createCollection("mycollection");
        log.info("集合创建成功");
    }

    public void getCollections(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        log.info("获取集合成功:{}",mycollection.getNamespace());
        MongoIterable<String> names = mongoDatabase.listCollectionNames();
        for (String name : names){
            log.info("循环集合名称:{}",name);
        }
    }

    public void insertDocument(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        Document document1 = new Document("name","lcl").append("age",18).append("city","bj");
        Document document2 = new Document("name","qmm").append("age",16).append("city","ly");
        Document document3 = new Document("name","zbx").append("age",27).append("city","zz");
        Document document4 = new Document("name","lmj").append("age",31).append("city","jx");

        Document document11 = new Document("name","lcl1").append("age",181).append("city","bj1");
        Document document21 = new Document("name","qmm1").append("age",161).append("city","ly1");
        Document document31 = new Document("name","zbx1").append("age",271).append("city","zz1");
        Document document41 = new Document("name","lmj1").append("age",311).append("city","jx1");

        Document document12 = new Document("name","lcl2").append("age",182).append("city","bj2");
        Document document22 = new Document("name","qmm2").append("age",162).append("city","ly2");
        Document document32 = new Document("name","zbx2").append("age",272).append("city","zz2");
        Document document42 = new Document("name","lmj2").append("age",312).append("city","jx2");

        Document document13 = new Document("name","lcl3").append("age",183).append("city","bj3");
        Document document23 = new Document("name","qmm3").append("age",163).append("city","ly3");
        Document document33 = new Document("name","zbx3").append("age",273).append("city","zz3");
        Document document43 = new Document("name","lmj3").append("age",313).append("city","jx3");
        List<Document> documentList = Arrays.asList(document1,document2,document3,document4);
        mycollection.insertMany(documentList);
        log.info("插入文档成功");
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("插入后的结果:【{}】", document.toJson());
        }
    }

    public void findDocument(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("文档循环结果:【{}】", document.toJson());
        }
    }

    public void updateDocument(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        mycollection.updateMany(Filters.eq("name","lcl"), new Document("age",31));
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("更新后的结果:【{}】", document.toJson());
        }
    }

    public void deleteDocument(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        mycollection.deleteMany(Filters.eq("city","jx"));
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("删除后的结果:【{}】", document.toJson());
        }
    }

    public void query(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        Document first = mycollection.find().first();
        log.info("查询第一条的city:{}",first.get("city"));
        //查询指定字段
        Document document = new Document().append("_id",0).append("city",0).append("name",1);
        FindIterable<Document> projection = mycollection.find().projection(document);
        for (Document document1 : projection){
            log.info("按条件输出结果:【{}】", document1.toJson());
        }
    }

    public void query1(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        //查询指定字段
        Document document = new Document().append("age",-1);
        FindIterable<Document> projection = mycollection.find().sort(document);
        for (Document document1 : projection){
            log.info("排序输出结果:【{}】", document1.toJson());
        }
    }

    public void likequery(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        Pattern pattern = Pattern.compile("^.*l.*$", Pattern.CASE_INSENSITIVE);
        BasicDBObject query = new BasicDBObject("name",pattern);
        FindIterable<Document> projection = mycollection.find(query);
        for (Document document1 : projection){
            log.info("模糊查询输出结果:【{}】", document1.toJson());
        }
    }

    public void page(){
        MongoDatabase mongoDatabase = client.getDatabase("lcltest5");
        MongoCollection<Document> mycollection = mongoDatabase.getCollection("mycollection");
        Pattern pattern = Pattern.compile("^.*l.*$", Pattern.CASE_INSENSITIVE);
        BasicDBObject query = new BasicDBObject("name",pattern);
        Document document = new Document().append("age",-1);
        FindIterable<Document> projection = mycollection.find(query).sort(document).skip(2).limit(3);
        for (Document document1 : projection){
            log.info("分页查询输出结果:【{}】", document1.toJson());
        }
    }

}

2、springboot集成mongodb(MongoTemplate)

  可以直接使用上面api中的命令,直接调用mongo客户端提供的api即可,和上面方法中唯一的区别就是这里直接使用了springboot提供的MongoTemplate

spring:
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017
      database: db6

 

@Service
@Slf4j
public class MongDBService {

    @Autowired
    private MongoTemplate mongoTemplate;

    public void createConnection(){
        MongoCollection<Document> mycollection = mongoTemplate.createCollection("lcltest5");
        log.info("集合创建成功");
    }

    public void getCollections(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        log.info("获取集合成功:{}",mycollection.getNamespace());

        Set<String> collectionNames = mongoTemplate.getCollectionNames();
        for (String name : collectionNames){
            log.info("循环集合名称:{}",name);
        }
    }

    public void insertDocument(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        Document document1 = new Document("name","lcl").append("age",18).append("city","bj");
        Document document2 = new Document("name","qmm").append("age",16).append("city","ly");
        Document document3 = new Document("name","zbx").append("age",27).append("city","zz");
        Document document4 = new Document("name","lmj").append("age",31).append("city","jx");

        Document document11 = new Document("name","lcl1").append("age",181).append("city","bj1");
        Document document21 = new Document("name","qmm1").append("age",161).append("city","ly1");
        Document document31 = new Document("name","zbx1").append("age",271).append("city","zz1");
        Document document41 = new Document("name","lmj1").append("age",311).append("city","jx1");

        Document document12 = new Document("name","lcl2").append("age",182).append("city","bj2");
        Document document22 = new Document("name","qmm2").append("age",162).append("city","ly2");
        Document document32 = new Document("name","zbx2").append("age",272).append("city","zz2");
        Document document42 = new Document("name","lmj2").append("age",312).append("city","jx2");

        Document document13 = new Document("name","lcl3").append("age",183).append("city","bj3");
        Document document23 = new Document("name","qmm3").append("age",163).append("city","ly3");
        Document document33 = new Document("name","zbx3").append("age",273).append("city","zz3");
        Document document43 = new Document("name","lmj3").append("age",313).append("city","jx3");
        List<Document> documentList = Arrays.asList(document1,document2,document3,document4,
                document11,document21,document31,document41,
                document12,document22,document32,document42);
        mycollection.insertMany(documentList);
        log.info("插入文档成功");
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("插入后的结果:【{}】", document.toJson());
        }
    }

    public void findDocument(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("文档循环结果:【{}】", document.toJson());
        }
    }

    public void updateDocument(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        mycollection.updateMany(Filters.eq("name","lcl"), new Document("$set",new Document("age",31)));
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("更新后的结果:【{}】", document.toJson());
        }
    }

    public void deleteDocument(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        mycollection.deleteMany(Filters.eq("city","jx"));
        FindIterable<Document> documents = mycollection.find();
        for (Document document : documents){
            log.info("删除后的结果:【{}】", document.toJson());
        }
    }

    public void query(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        Document first = mycollection.find().first();
        log.info("查询第一条的city:{}",first.get("city"));
        //查询指定字段
        Document document = new Document().append("_id",0).append("city",1).append("name",1);
        FindIterable<Document> projection = mycollection.find().projection(document);
        for (Document document1 : projection){
            log.info("按条件输出结果:【{}】", document1.toJson());
        }
    }

    public void query1(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        //查询指定字段
        Document document = new Document().append("age",-1);
        FindIterable<Document> projection = mycollection.find().sort(document);
        for (Document document1 : projection){
            log.info("排序输出结果:【{}】", document1.toJson());
        }
    }

    public void likequery(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        Pattern pattern = Pattern.compile("^.*l.*$", Pattern.CASE_INSENSITIVE);
        BasicDBObject query = new BasicDBObject("name",pattern);
        FindIterable<Document> projection = mycollection.find(query);
        for (Document document1 : projection){
            log.info("模糊查询输出结果:【{}】", document1.toJson());
        }
    }

    public void page(){
        MongoCollection<Document> mycollection = mongoTemplate.getCollection("lcltest5");
        Pattern pattern = Pattern.compile("^.*l.*$", Pattern.CASE_INSENSITIVE);
        BasicDBObject query = new BasicDBObject("name",pattern);
        Document document = new Document().append("age",-1);
        FindIterable<Document> projection = mycollection.find(query).sort(document).skip(2).limit(3);
        for (Document document1 : projection){
            log.info("分页查询输出结果:【{}】", document1.toJson());
        }
    }

    public void maintest(){
        createConnection();
        getCollections();
        insertDocument();
        findDocument();
        updateDocument();
        deleteDocument();
        query();
        query();
        likequery();
        page();
    }
}

  实际开发中,这样用非常不方便

3、springboot集成mongodb(MongoRepository)

@RequiredArgsConstructor
@Service
@Slf4j
public class MongoService2 {

    private final UserRepository userRepository;

  public void insertDocument(){ userRepository.insert(UserDo.builder()._id("1").name("lcl").city("bj").age(18).build()); userRepository.insert(UserDo.builder()._id("2").name("1mm").city("ly").age(15).build()); userRepository.insert(UserDo.builder()._id("3").name("zbx").city("zz").age(22).build()); userRepository.insert(UserDo.builder()._id("4").name("lcl1").city("bj1").age(181).build()); userRepository.insert(UserDo.builder()._id("5").name("1mm1").city("ly1").age(151).build()); userRepository.insert(UserDo.builder()._id("6").name("zbx1").city("zz1").age(221).build()); userRepository.insert(UserDo.builder()._id("7").name("lcl1").city("bj1").age(181).build()); userRepository.insert(UserDo.builder()._id("8").name("1mm1").city("ly1").age(151).build()); userRepository.insert(UserDo.builder()._id("9").name("zbx1").city("zz1").age(221).build()); log.info("插入文档成功"); List<UserDo> userDoList = userRepository.findAll(); for (UserDo userDo : userDoList){ log.info("插入后的结果:【{}】", JSON.toJSONString(userDo)); } } public void findDocument(){ List<UserDo> userDoList = userRepository.findAll(); for (UserDo userDo : userDoList){ log.info("文档循环结果:【{}】", JSON.toJSONString(userDo)); } } public void updateDocument(){ Optional<UserDo> userDoOptional = userRepository.findById("1"); if(userDoOptional.isPresent()){ UserDo userDo = userDoOptional.get(); userDo.setCity("beijing"); UserDo save = userRepository.save(userDo); log.info("更新后的结果:【{}】", JSON.toJSONString(save)); } List<UserDo> userDoList = userRepository.findAll(); for (UserDo userDo : userDoList){ log.info("更新后的结果:【{}】", JSON.toJSONString(userDo)); } } public void deleteDocument(){ ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("_id","name","age","city"); Example<UserDo> userDoExample = Example.of(UserDo.builder().name("lcl1").build(), matcher); Optional<UserDo> userDoOptional = userRepository.findOne(userDoExample); if(userDoOptional.isPresent()){ userRepository.delete(userDoOptional.get()); } List<UserDo> userDoList = userRepository.findAll(); for (UserDo userDo : userDoList){ log.info("删除后的结果:【{}】", JSON.toJSONString(userDo)); } } public void query1(){ Sort.Order order = new Sort.Order(Sort.Direction.ASC, "age"); Sort sort = Sort.by(order); List<UserDo> userDoList = userRepository.findAll(sort); for (UserDo userDo : userDoList){ log.info("排序输出结果:【{}】", JSON.toJSONString(userDo)); } } public void likequery(){ List<UserDo> userDoList = userRepository.findUserByNameLike("l"); for (UserDo userDo : userDoList){ log.info("模糊查询输出结果:【{}】", JSON.toJSONString(userDo)); } } public void page(){ PageRequest pageRequest = PageRequest.of(2,3); Page<UserDo> userDos = userRepository.findAll(pageRequest); List<UserDo> userDoList = userDos.getContent(); for (UserDo userDo : userDoList){ log.info("分页查询输出结果:【{}】", JSON.toJSONString(userDo)); } } }
@Repository
public interface UserRepository extends MongoRepository<UserDo, String> {

    List<UserDo> findUserByNameLike(String STR);
}

 

posted @ 2021-02-06 01:08  李聪龙  阅读(223)  评论(0编辑  收藏  举报