超详细,mongodb安装部署+入门操作+springboot整合

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

在高负载的情况下,添加更多的节点,可以保证服务器性能。

MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

img

主要特点

  • 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安装简单。

windows安装

官网下载安装文件或者压缩包即可

安装有两种方式:

方式一:

在安装路径的bin同级目录下新建两级文件夹:data/db
然后进入bin目录打开命令窗口,输入命令
mongod --dbpath ..\data\db

方式二:

首先在bin同级目录下新建config文件夹中新建mongod.conf配置文件,编辑

storage:
    dbPath: D:\environment\MongoDB\data\db

然后到bin目录下打开命令窗口,输入以下命令行启动

mongod -f ..\config\mongod.conf

完成启动,发现mongodb的默认端口号是27017

开启了mongodb服务之后,该怎么连接呢,连接也有两种方式

方式一:

打开bin目录下的mongo.exe,直接输入以下命令就可以连接(甚至自动连接)

mongo

测试是否连接成功

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

方式二:

可通过可视化工具来连接,需要下载compass,在官网下载解压即用,运行compass.exe文件,然后conect即可
在这里插入图片描述

Linux安装

官网下载linux版本的mongodb

将压缩包放到linux系统中的usr/local/mongodb文件夹中,解压

cd /usr/local/mongodb
tar -xvf mongodb-linux-x86_64-4.0.10.tgz

新家几个目录,分别用来存储数据、日志和配置

mkdir -p /usr/local/mongodb/data
mkdir -p /usr/local/mongodb/log

在bin目录下新建并修改配置文件

vim /usr/local/mongodbmongodb-linux-x86_64-4.0.19/bin/mongod.conf

内容如下:

systemLog:
  #MongoDB发送所有日志输出的目标指定为文件
  destination: file
  path: "/usr/local/mongodb/log/mongod.log"
  # 当mongoos或mongod实例重新启动时,会将新条目附加到先有日志文件的末尾
  logAppend: true
storage:
  #mongod实例存储其数据的目录
  dbPath: "/usr/local/mongodb/data/db"
  journal:
    #启用或禁用持久性日志以确保数据文件保持有效和可恢复。 
    enabled: true
processManagement: 
   #启用在后台运行mongos或mongod进程的守护进程模式。 
   fork: true
net:
   #服务实例绑定的IP,默认是localhost 
   bindIp: localhost,172.16.0.17
   port: 27017

启动MongoDB服务

./mongod -f ./mongod.conf

启动成功

测试是否启动成功:

ps -ef|grep mongod

最后通过可视化界面来检测我们的mongodb,这时候不再是localhost了,而是要连接到我们的远程服务器上,需要填写远程服务器的主机名

连接成功

最后看下怎么关闭服务

方式一:

kill -2 进程id

方式二:

mongo --port 27017 
//#切换到admin库 
use admin 
//关闭服务 
db.shutdownServer()

数据库的创建和删除

存放文章评论的数据存放到MongoDB中,数据结构参考如下:

数据库:articledb
在这里插入图片描述

选择和创建数据库

如果数据库不存在则自动创建

use articledb
查看数据库

查看有权限查看的所有的数据库命令

show dbs

注意:如果是空的db是不会显示出来的,例如刚刚创建的articledb,因为刚创建还没数据,也就是还没持久化到磁盘中,暂存在内存中

查看正在使用的数据库

db
删除数据库

MongoDB 删除数据库的语法格式如下:

db.dropDatabase()

提示:主要用来删除已经持久化的数据库

集合

创建集合

集合,类似关系型数据库中的表。 可以显示的创建,也可以隐式的创建

显式创建、查看、删除
> db.createCollection("my")
{ "ok" : 1 }
> show collections # 查看集合
my
> db.my.drop()
true
> show collections
>

集合的命名规范:

  • 集合名不能是空字符串""。
  • 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
  • 集合名不能以"system."开头,这是为系统集合保留的前缀。
  • 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除 非你要访问这种系统创建的集合,否则千万不要在名字里出现$。

隐式创建

当向一个集合中插入一个文档的时候,如果集合不存在,则会自动创建集合,通常我们使用隐式创建文档即可

文档操作

文档(document)的数据结构和 JSON 基本一样。 所有存储在集合中的数据都是 BSON 格式

插入文档

跟mysql一样既可以单条插入,也可以多条执行

单条插入

使用insert() 或 save() 方法向集合中插入文档,语法如下:

db.collection.insert( 
    <document or array of documents>, 
    { 
    	writeConcern: <document>, 
    	ordered: <boolean> 
    }
)

参数:
在这里插入图片描述
示例:

要想comment的集合中插入一条测试数据(隐式插入)

> db.comment.insert({
...     "articleid": "100000",
...     "content": "今天天气真好,阳光明 媚",
...     "userid": "1001",
...     "nickname": "Rose",
...     "createdatetime": new Date(),
...     "likenum": NumberInt(10),
...     "state": null
... })
WriteResult({ "nInserted" : 1 }) # 表明插入成功
> show collections
comment
>

提示:

  • comment集合如果不存在,则会隐式创建
  • mongo中的数字,默认double类型,如要存整型,必须使用函数NumberInt,否则取出来就有问题了。
  • 插入当前日期使用 new Date()
  • 插入的数据没有指定 _id ,会自动生成主键值
  • 如果某字段没值,可以赋值为null,或不写该字段。

注意:

  1. 文档中的键/值对是有序的。
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB区分类型和大小写。
  4. MongoDB的文档不能有重复的键。
  5. 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

  • 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
  • .和$有特别的意义,只有在特定环境下才能使用。
  • 以下划线"_"开头的键是保留的(不是严格要求的)
批量插入

语法:

db.collection.insertMany(
    [ <document 1> , <document 2>, ... ], 
    { writeConcern: <document>, ordered: <boolean> }
)

示例:

> db.comment.insertMany([{
...     "_id": "1",
...     "articleid": "100001",
...     "content": "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。",
...     "userid": "1002",
...     "nickname": "相忘于江湖",
...     "createdatetime": new Date("2019-08- 05T22:08:15.522Z"),
...     "likenum": NumberInt(1000),
...     "state": "1"
... },
... {
...     "_id": "2",
...     "articleid": "100001",
...     "content": "我夏天空腹喝凉开水,冬天喝温开水",
...     "userid": "1005",
...     "nickname": "伊人憔 悴",
...     "createdatetime": new Date("2019-08-05T23:58:51.485Z"),
...     "likenum": NumberInt(888),
...     "state": "1"
... },
... {
...     "_id": "3",
...     "articleid": "100001",
...     "content": "我一直喝凉开水,冬天夏天都喝。",
...     "userid": "1004",
...     "nickname": "杰克船 长",
...     "createdatetime": new Date("2019-08-06T01:05:06.321Z"),
...     "likenum": NumberInt(666),
...     "state": "1"
... },
... {
...     "_id": "4",
...     "articleid": "100001",
...     "content": "专家说不能空腹吃饭,影响健康。",
...     "userid": "1003",
...     "nickname": "凯 撒",
...     "createdatetime": new Date("2019-08-06T08:18:35.288Z"),
...     "likenum": NumberInt(2000),
...     "state": "1"
... },
... {
...     "_id": "5",
...     "articleid": "100001",
...     "content": "研究表明,刚烧开的水千万不能喝,因为烫 嘴。",
...     "userid": "1003",
...     "nickname": "凯撒",
...     "createdatetime": new Date("2019-08- 06T11:01:02.521Z"),
...     "likenum": NumberInt(3000),
...     "state": "1"
... }]);
{
        "acknowledged" : true,
        "insertedIds" : [
                "1",
                "2",
                "3",
                "4",
                "5"
        ]
}

提示:

插入时指定了 _id ,则主键就是该值。

如果某条数据插入失败,将会终止插入,但已经插入成功的数据不会回滚掉。

因为批量插入由于数据较多容易出现失败,因此,可以使用try catch进行异常捕捉处理,测试的时候可以不处理。

try {  
    db.comment.insertMany([{
    "_id": "1",
    "articleid": "100001",
    "content": "我们不应该把清晨浪费在手机上,健康很重要",
    "userid": "1002",
    "nickname": "相忘于江湖",
    "createdatetime": new Date("2019-08- 05T22:08:15.522Z"),
    "likenum": NumberInt(1000),
    "state": "1"
    },
    {
        "_id": "2",
        "articleid": "100001",
        "content": "我夏天空腹喝凉开水,冬天喝温开水",
        "userid": "1005",
        "nickname": "伊人憔 悴",
        "createdatetime": new Date("2019-08-05T23:58:51.485Z"),
        "likenum": NumberInt(888),
        "state": "1"
    },
    {
        "_id": "3",
        "articleid": "100001",
        "content": "我一直喝凉开水,冬天夏天都喝。",
        "userid": "1004",
        "nickname": "杰克船 长",
        "createdatetime": new Date("2019-08-06T01:05:06.321Z"),
        "likenum": NumberInt(666),
        "state": "1"
    },
    {
        "_id": "4",
        "articleid": "100001",
        "content": "专家说不能空腹吃饭,影响健康。",
        "userid": "1003",
        "nickname": "凯 撒",
        "createdatetime": new Date("2019-08-06T08:18:35.288Z"),
        "likenum": NumberInt(2000),
        "state": "1"
    },
    {
        "_id": "5",
        "articleid": "100001",
        "content": "研究表明,刚烧开的水千万不能喝,因为烫 嘴。",
        "userid": "1003",
        "nickname": "凯撒",
        "createdatetime": new Date("2019-08- 06T11:01:02.521Z"),
        "likenum": NumberInt(3000),
        "state": "1"
    }]);
} catch (e) { 
    print (e); 
}
查询文档

查询数据的语法格式如下:

db.collection.find(<query>, [projection])

参数:

ParameterTypeDescription
querydocument可选。使用查询运算符指定选择筛选器。若要返回集合中的所有文档,请省略此参数或传递空文档 ({})
projectiondocument可选。指定要在与查询筛选器匹配的文档中返回的字段(投影)。若要返回匹配文档中的所有字段,

示例:

查询所有

如果我们要查询集合的所有文档,我们输入以下命令

db.comment.find() 
# 或
db.comment.find({})

这里你会发现每条文档会有一个叫_id的字段,这个相当于我们原来关系数据库中表的主键,当你在插入文档记录时没有指定该字段, MongoDB会自动创建,其类型是ObjectID类型。 如果我们在插入文档记录时指定该字段也可以,其类型可以是ObjectID类型,也可以是MongoDB支持的任意类型.

如果我想按一定条件来查询,比如我想查询userid为1003的记录,怎么办?很简单!只 要在fifind()中添加参数即可,参数也是json格式,如 下:

> db.comment.find({userid:"1003"})
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯 撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }
查询单条

如果你只需要返回符合条件的第一条数据,我们可以使用fifindOne命令来实现,语法和fifind一样。

如:查询用户编号是1003的记录,但只最多返回符合条件的第一条记录:

> db.comment.findOne({userid:"1003"})
{
        "_id" : "4",
        "articleid" : "100001",
        "content" : "专家说不能空腹吃饭,影响健康。",
        "userid" : "1003",
        "nickname" : "凯 撒",
        "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"),
        "likenum" : 2000,
        "state" : "1"
}
>
投影查询

如果要查询结果返回部分字段,则需要使用投影查询(不显示所有字段,只显示指定的字段)。

如:查询结果只显示 _id、userid、nickname :

> db.comment.find({userid:"1003"},{userid:1,nickname:1})
{ "_id" : "4", "userid" : "1003", "nickname" : "凯 撒" }
{ "_id" : "5", "userid" : "1003", "nickname" : "凯撒" }

如:查询结果只显示 、userid、nickname ,不显示 _id :

> db.comment.find({userid:"1003"},{userid:1,nickname:1,_id:0})
{ "userid" : "1003", "nickname" : "凯 撒" }
{ "userid" : "1003", "nickname" : "凯撒" }

再例如:查询所有数据,但只显示 _id、userid、nickname :

db.comment.find({},{userid:1,nickname:1})
统计查询

语法:

db.collection.count(query, options)

参数:

ParameterTypeDescription
querydocument查询选择条件。
optionsdocument可选。用于修改计数的额外选项。

示例:

统计comment集合的所有的记录数

> db.comment.count()
6
> db.comment.count({userid:"1003"})
2
>
分页查询

可以使用limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据

基本语法如下所示:

db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

如果你想返回指定条数的记录,可以在fifind方法后调用limit来返回结果(TopN),默认值20,例如

> db.comment.find().limit(3)
{ "_id" : ObjectId("5eee1393b9ba7b116ffa7823"), "articleid" : "100000", "content" : "今天天气真好,阳光明 媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2020-06-20T13:48:03.665Z"), "likenum" : 10, "state" : null }
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 1000, "state" : "1" }
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
>

skip方法同样接受一个数字参数作为跳过的记录条数。(前N个不要),默认值是0

> db.comment.find().skip(3)
{ "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船 长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯 撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }
排序查询

sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用 于降序排列

db.COLLECTION_NAME.find().sort({KEY:1}) 

例如:

对userid降序排列,并对访问量进行升序排列

> db.comment.find().sort({userid:-1,likenum:1})
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
{ "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船 长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯 撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 1000, "state" : "1" }
{ "_id" : ObjectId("5eee1393b9ba7b116ffa7823"), "articleid" : "100000", "content" : "今天天气真好,阳光明 媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2020-06-20T13:48:03.665Z"), "likenum" : 10, "state" : null }
>

提示:

skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit(),和命令编写顺序无关。

正则查询

MongoDB的模糊查询是通过正则表达式的方式实现的。格式为:

db.collection.find({field:/正则表达式/})

提示:正则表达式是js的语法,直接量的写法。

例如,我要查询评论内容包含“开水”的所有文档,代码如下:

> db.comment.find({content:/空腹/})
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯 撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
> db.comment.find({content:/^我们/})
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 1000, "state" : "1" }
>
比较查询

<, <=, >, >= 这个操作符也是很常用的,格式如下:

db.集合名称.find({ "field" : { $gt: value }}) // 大于: field > value 
db.集合名称.find({ "field" : { $lt: value }}) // 小于: field < value 
db.集合名称.find({ "field" : { $gte: value }}) // 大于等于: field >= value 
db.集合名称.find({ "field" : { $lte: value }}) // 小于等于: field <= value 
db.集合名称.find({ "field" : { $ne: value }}) // 不等于: field != value

示例:查询评论点赞数量大于700的记录

> db.comment.find({likenum:{$gt:NumberInt(700)}})
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 1000, "state" : "1" }
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯 撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }
>
包含查询

包含使用$in操作符。 示例:查询评论的集合中userid字段包含1003或1004的文档

> db.comment.find({userid:{$in:["1003","1004"]}})
{ "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船 长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯 撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }
>
条件连接查询

我们如果需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。 格式为:

$and:[ { },{ },{ } ] 

示例:查询评论集合中likenum大于等于700 并且小于2000的文档:

> db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]})
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 1000, "state" : "1" }
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
>

如果两个以上条件之间是或者的关系,我们使用 操作符进行关联,与前面 and的使用方式相同 格式为:

$or:[ { },{ },{ } ]
修改文档
db.collection.update(query, update, options) 
或 
db.collection.update( 
    <query>, 
    <update>, 
    { 
        upsert: <boolean>, 
        multi: <boolean>, 
        writeConcern: <document>, 
        collation: <document>, 
        arrayFilters: [ <filterdocument1>, ... ], 
        hint: <document|string> // Available starting in MongoDB 4.2 
    }
)
覆盖修改

如果我们想修改_id为1的记录,点赞量为1001,输入以下语句:

> db.comment.update({_id:"1"},{likenum:NumberInt(1001)})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.comment.findOne({_id:"1"})
{ "_id" : "1", "likenum" : 1001 }
>

执行后,我们会发现,这条文档除了likenum字段其它字段都不见了

局部修改

为了解决这个问题,我们需要使用修改器$set来实现,命令如下:

我们想修改_id为2的记录,浏览量为889,输入以下语句:

> db.comment.update({_id:"2"},{$set:{likenum:NumberInt(889)}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.comment.findOne({_id:"2"})
{
        "_id" : "2",
        "articleid" : "100001",
        "content" : "我夏天空腹喝凉开水,冬天喝温开水",
        "userid" : "1005",
        "nickname" : "伊人憔 悴",
        "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"),
        "likenum" : 889,
        "state" : "1"
}
>
批量修改

更新所有用户为 1003 的用户的昵称为 凯撒大帝 。

> db.comment.update({userid:"1003"},{$set:{nickname:"凯撒2"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.comment.find({userid:"1003"})
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯撒2", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }
> db.comment.update({userid:"1003"},{$set:{nickname:"凯撒大帝"}},{multi:true})
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })
>  db.comment.find({userid:"1003"})
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯撒大帝", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫 嘴。", "userid" : "1003", "nickname" : "凯撒大帝", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 3000, "state" : "1" }
>

提示:如果不加后面的参数,则只更新符合条件的第一条记录

列值增长的修改

如果我们想实现对某列值在原有值的基础上进行增加或减少,可以使用 $inc 运算符来实现。

需求:对3号数据的点赞数,每次递增1

> db.comment.update({_id:"3"},{$inc:{likenum:Number(1)}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>
删除文档

删除文档的语法结构:

db.集合名称.remove(条件)

以下语句可以将数据全部删除,请慎用

db.comment.remove({})

如果删除_id=1的记录,输入以下语句

> db.comment.remove({_id:"1"})
WriteResult({ "nRemoved" : 1 })
>

常用命令小结

选择切换数据库:

use articledb 

插入数据:

db.comment.insert({bson数据}) 

查询所有数据:

db.comment.find()

条件查询数据:

db.comment.find({条件}) 

查询符合条件的第一条记录:

db.comment.findOne({条件}) 

查询符合条件的前几条记录:

db.comment.find({条件}).limit(条数)

查询符合条件的跳过的记录:

db.comment.find({条件}).skip(条数) 

修改数据:

db.comment.update({条件},{修改后的数据}) 
或
db.comment.update({条件},{$set:{要修改部分的字段:数据}) 

修改数据并自增某字段值:

db.comment.update({条件},{$inc:{自增的字段:步进值}}) 

删除数据:

db.comment.remove({条件}) 

统计查询:

db.comment.count({条件}) 

模糊查询:

db.comment.find({字段名:/正则表达式/}) 

条件比较运算:

db.comment.find({字段名:{$gt:值}}) 

包含查询:

db.comment.find({字段名:{$in:[值1,值2]}})
或
db.comment.find({字段名:{$nin:[值1,值2]}}) 

条件连接查询:

db.comment.find({$and:[{条件1},{条件2}]})
或
db.comment.find({$or:[{条件1},{条件2}]})

索引

索引支持在MongoDB中高效地执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

如果查询存在适当的索引,MongoDB可以使用该索引限制必须检查的文档数。

索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。

官网文档:https://docs.mongodb.com/manual/indexes/

MongoDB索引使用B树数据结构(确切的说是B-Tree,MySQL是B+Tree)

索引的类型
单字段索引

MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index)。

对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。

复合索引

MongoDB还支持多个字段的用户定义索引,即复合索引(Compound Index)。

复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然后在每个userid的值内,再在按score倒序排序

其他索引

地理空间索引(Geospatial Index)、文本索引(Text Indexes)、哈希索引(Hashed Indexes)。

地理空间索引

为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面 几何的二维球面索引。

文本索引

MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如“the”、“a”、“or”),而将集合中的词作为词干,只存储根词。

哈希索引

为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支 持相等匹配,不支持基于范围的查询。

索引管理
查询索引

返回一个集合中的所有索引的数组

> db.comment.getIndexes()
[
        {
                "v" : 2, # 索引引擎版本
                "key" : {
                        "_id" : 1 # 索引对应的字段:1代表升序
                },
                "name" : "_id_", # 索引名称
                "ns" : "test.comment"
        }
]
>

结果中显示的是默认 _id 索引。

默认_id索引:

MongoDB在创建集合的过程中,在 _id 字段上创建一个唯一的索引,默认名字为 id ,该索引可防止客户端插入两个具有相同值的文 档,您不能在_id字段上删除此索引。

注意:该索引是唯一索引,因此值不能重复,即 _id 值不能重复的。在分片集群中,通常使用 _id 作为片键

创建索引

在集合上创建索引。

db.collection.createIndex(keys, options)

在集合上创建索引。

db.collection.createIndex(keys, options)

参数:
在这里插入图片描述
options(更多选项)列表:
在这里插入图片描述
提示:

注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex() ,之后的版本使用了 db.collection.createIndex() 方法, ensureIndex() 还能用,但只是createIndex() 的别名。

【示例】

(1)单字段索引示例:对 userid 字段建立索引:

db.comment.createIndex({userid:1}) 
{ 
	"createdCollectionAutomatically" : false, 
	"numIndexesBefore" : 1, 
	"numIndexesAfter" : 2, 
	"ok" : 1 
}

(2)复合索引:对 userid 和 nickname 同时建立复合(Compound)索引:

db.comment.createIndex({userid:1,nickname:-1}) 
{ 
	"createdCollectionAutomatically" : false, 
	"numIndexesBefore" : 2, 
	"numIndexesAfter" : 3, 
	"ok" : 1 
}
索引的移除

可以移除指定的索引,或移除所有索引

移除指定索引:

db.collection.dropIndex(index)

移除所有索引:

注意:_id的索引是不会被删除的

db.collection.dropIndexes()

索引的使用

执行计划

分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。

那么,通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划查看

db.collection.find(query,options).explain(options)

示例:

查看根据userid查询数据的情况:

> db.comment.find({userid:"1003"}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test.comment",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "userid" : {
                                "$eq" : "1003"
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "userid" : {
                                        "$eq" : "1003"
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "ryan",
                "port" : 27017,
                "version" : "4.0.19",
                "gitVersion" : "7e28f4296a04d858a2e3dd84a1e79c9ba59a9568"
        },
        "ok" : 1
}

关键点看: “stage” : “COLLSCAN”, 表示全集合扫描,也就是全部5条数据都要查一遍,再选择符合条件的,这个查询方式就比较低了
在这里插入图片描述
我们尝试给userid加上索引,再查一下看看

> db.comment.createIndex({userid:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}

在这里插入图片描述
再次查看执行计划,关键点看: “stage” : “IXSCAN” ,基于索引的扫描,然后抓取fetch

这时候会先去索引库中扫描数据,再抓取符合条件的数据,总共才查了2条数据,对比没有索引的,效率肯定是提高了,如果是大数据,就会非常明显

涵盖的查询

当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存,这些覆盖的查询非常高效
在这里插入图片描述
示例:
在这里插入图片描述

springboot整合MongoDB

主要结合springboot-mangodb对数据的操作

表结构分析
在这里插入图片描述
技术选型

SpringDataMongoDB

实战:

1、创建项目,导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.ryan</groupId>
    <artifactId>mongodb-study</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <!-- this is needed or IntelliJ gives junit.jar or junit-platform-launcher:1.3.2 not found errors -->
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <scope>test</scope>
        </dependency>


    </dependencies>

</project>

2、配置yml文件

spring:
  # 数据源配置
  data:
    mongodb:
      # 主机地址
      host: 203.195.160.231
      # 数据库
      database: test
      # 默认端口号:27017
      port: 27017

3、编写主启动类

@SpringBootApplication
public class ArticleApplication {
     public static void main(String[] args) {
           SpringApplication.run(ArticleApplication.class, args);
      }
}

4、编写实体类

注意:由于是非关系型数据库,所以实体类属性和mongodb数据库中已经存在的字段不需要不一定要保持一致

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "comment")//指定对应的集合
@CompoundIndex(def = "{'userid':1, 'nickname':-1}")//也可以在类上添加索引
@Accessors(chain = true)//支持链式编程
public class Comment implements Serializable {

    //@Id
    private String id;//主键,_id,如果属性名时id,可以省略注解@Id
    @Field("content")
    private String content;//如果属性名称和集合中的字段名字不一样,可以像这样添加注解
    private Date publishtime;
    @Indexed
    private String userid;//添加索引,一般会通过命令行去添加索引
    private String nickname;
    private LocalDateTime createdatetime;
    private Integer likenum;
    private Integer replynum;
    private String parentid;
    private String articleid;
}

5、编写dao层

//评论的持久层接口
public interface CommentDao extends MongoRepository<Comment, String> {
    
    //继承MongoRepository之后已经继承了很多crud方法,具体可以点进去查看

    //如果想要实现分页查询,我们需要另增方法,注意方法名格式是有要求的,findBy+字段名
    Page<Comment> findByUserid(String userid, Pageable pageable);

}

6、编写service层

@Service
public class CommentService {

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private MongoTemplate mongoTemplate;

    //调用dao的方法,都是通过dao继承MongoRepository过来的
    //增
    public void saveComment(Comment comment){
        commentDao.save(comment);
    }

    //更新
    public void updateComment(Comment comment){
        commentDao.save(comment);
    }

    //根据id删除
    public void deleteCommentById(String id){
        commentDao.deleteById(id);
    }

    //删除所有
    public void deleteAllComments(){
        commentDao.deleteAll();
    }

    //根据id查询
    public Comment findById(String id){
        return commentDao.findById(id).get();
    }

    //查询所有
    public List<Comment> findAll(){
        return commentDao.findAll();
    }

    //分页查询
    public Page<Comment> findByPage(String userid, int pageNo, int pageSize){
        return commentDao.findByUserid(userid, PageRequest.of(pageNo,pageSize));
    }

    //实现点赞+1
    public void updateCommentLikenum(String id){
        //查询条件
        Query query = Query.query(Criteria.where("_id").is(id));//查询的条件,如果是多个条件,可以在后面addCriteria
        //更新条件
        Update update = new Update();
        update.inc("likenum");//自增1
        //执行更新
        mongoTemplate.updateFirst(query, update, Comment.class);
    }

}

7、测试

@SpringBootTest
public class ArticleApplicationTests {

    @Resource
    private CommentService commentService;

    @Test
    void test1(){
        Comment comment = new Comment();
        comment.setContent("ryan自学java")
                .setPublishtime(new Date())
                .setUserid("10086")
                .setNickname("牛排")
                .setCreatedatetime(LocalDateTime.now())
                .setLikenum(999)
                .setReplynum(40)
                .setArticleid("9527");
        commentService.saveComment(comment);
    }

    //其他的crud方法就不一一测试了
    //如果想要实现分页查询,可以通过在dao层自定义一个方法查询

    //另外如果想通过mongodb实现点赞数+1的话,原生的+1方法效率比较低,这时候我们可以通过MongoTemplate来实现
    @Test
    void testAddLikenum(){
        commentService.updateCommentLikenum("2");
    }
}

注意:

  • 测试前,别忘了开mongodb的服务哦,我这里是将mongodb部署到远程服务上的
  • 另外可以结合可视化工具compass方便查看数据哦

以上是mongodb的简单入门,先写到这里,后续会再进一步学习mongodb

如果需要获取相关资料的也可以私信我哦,觉得可以帮助到你的话麻烦帮忙点个赞

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值