目 录CONTENT

文章目录

MongoDB急速入门

phyger
2022-06-28 / 0 评论 / 1 点赞 / 750 阅读 / 12,987 字 / 正在检测是否收录...

1、前言

前面我们已经介绍过缓存k-v数据库Redis,华为的OpenGauss关系型数据库,今天我们继续介绍一款NoSQL数据库MongoDB。

MongoDB是一款NoSQL(Not Only SQL)数据库。

其拥有很多的优点:

  • 扩展性强
  • 高性能
  • 分布式(HA)

但是其也拥有一些缺点:

  • 事务能力弱
  • 占用空间大
  • 不支持热重启

即便如此,也不妨碍它是一款强大,优秀的文档型数据库的客观事实。

2、快速开始

为了方便,我们这里使用windows版本的MongoDB来做学习演示。

2.1、下载MongoDB_Windows版本

从以下链接下载MongoDB社区程序.zip

MongoDB的下载中心

  1. 版本下拉列表中,选择要下载的MongoDB版本。
  2. 平台下拉菜单中,选择Windows
  3. Package下拉列表中,选择zip
  4. 点击下载

以上步骤摘自:MongoDB中文社区

以上步骤很是清楚,但是我的网络无法完成下载,慢的和蜗牛一样。索性我选择了XX下载之家不到5分钟就完成了下载。

下载完成后,我们将MongoDB的zip包解压,然后把解压后的MongoDB文件中的bin路径添加到环境变量即可。

2.2、启动MongoDB

2.2.1、启动服务端

PS E:\demo> mkdir db
PS E:\demo> mongod --dbpath db

在windows terminal中执行上述命令,出现waiting for connections on port 27017即证明MongoDB服务端启动成功。

2.2.2、使用客户端连接

PS E:\> mongo
MongoDB shell version v4.0.3
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID("c752f19d-cfde-4b8f-85ca-48372e273eed") }
MongoDB server version: 4.0.3
...省略...
>

没错,就是这么简单,MongoDB连接完成。

2.3、基础命令

2.3.1、查看数据库

> db             # 查看当前所在的数据库
test
> show dbs       # 查看所有数据库
admin   0.000GB
config  0.000GB
local   0.000GB
> 

如上,你发现了什么问题没有?

为什么当前所在的数据库是test,但是所有数据库中没有test库。经过验证,当数据库中没有数据的时候就会不展示。

那我们向其中插入一些数据看看效果?

2.3.2、数据插入和查询

> db.test.insert({"name":"phyger","age":18})    # 数据插入
WriteResult({ "nInserted" : 1 })
> db.test.find()                                # 数据查询
{ "_id" : ObjectId("62bac83d6e89996fc64680e6"), "name" : "phyger", "age" : 18 }
> db.test.find({"name":"phyger"})               # 根据name查询
{ "_id" : ObjectId("62bac83d6e89996fc64680e6"), "name" : "phyger", "age" : 18 }
> db.test.find({"age":18})                      # 根据年龄查询
{ "_id" : ObjectId("62bac83d6e89996fc64680e6"), "name" : "phyger", "age" : 18 }
> db.test.find().pretty()                       # 查询结果美化pretty
{
        "_id" : ObjectId("62bac83d6e89996fc64680e6"),
        "name" : "phyger",
        "age" : 18
}
>

save方法,插入:

> db.test.find().pretty()
{
        "_id" : ObjectId("62bac979b63fec7fa1ee0c47"),
        "name" : "phyger-2",
        "age" : 20
}
{ "_id" : ObjectId("62bad0b8b63fec7fa1ee0c4a"), "name" : "phyger-2" }
> db.test.insert({"_id":ObjectId("62bad0b8b63fec7fa1ee0c4a"),"name":"phyger-3"})    # 使用重复的id插入,会保存
WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 11000,
                "errmsg" : "E11000 duplicate key error collection: test.test index: _id_ dup key: { : ObjectId('62bad0b8b63fec7fa1ee0c4a') }"
        }
})
> db.test.save({"_id":ObjectId("62bad0b8b63fec7fa1ee0c4a"),"name":"phyger-3"})    # 使用重复的id保存,会更新
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>

insert和save的区别:

insert在id重复的时候,不允许插入;save在id重复的时候,会更新。

2.3.3、更新数据

更新数据的语法格式:

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

justOne:默认为false,会删除匹配到的所有对象;如果指定为true或者1,则只会删除匹配到的第一个对象。

writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。

> db.test.update({"name":"phyger"},{$set:{"name":"phyger-0"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.test.find().pretty()
{
        "_id" : ObjectId("62bac83d6e89996fc64680e6"),
        "name" : "phyger-0",
        "age" : 18
}
{
        "_id" : ObjectId("62bac979b63fec7fa1ee0c47"),
        "name" : "phyger-2",
        "age" : 20
}
{
        "_id" : ObjectId("62bac98bb63fec7fa1ee0c48"),
        "name" : "phyger-1",
        "age" : 19,
        "home" : "china"
}
>

如上,使用了update{query,update}语句将查询到的对象进行了修改。

$set:{update}中的$set:的作用就是指定字段修改,如果不带$set:,那么被查询到的对象将会被update覆盖,即会丢失其他字段。

就像这样:

> db.test.update({"name":"phyger-0"},{"name":"phyger-00"})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.test.find().pretty()
{ "_id" : ObjectId("62bac83d6e89996fc64680e6"), "name" : "phyger-00" }
{
        "_id" : ObjectId("62bac979b63fec7fa1ee0c47"),
        "name" : "phyger-2",
        "age" : 20
}
{
        "_id" : ObjectId("62bac98bb63fec7fa1ee0c48"),
        "name" : "phyger-1",
        "age" : 19,
        "home" : "china"
}
>

Oops,phyger-0对象原有的age字段被更新丢了。即全量更新了。

当我们查询到有多个数据的时候,怎么更新呢?

> db.test.find().pretty()
{
        "_id" : ObjectId("62bac83d6e89996fc64680e6"),
        "name" : "phyger-0",
        "age" : 19
}
{
        "_id" : ObjectId("62bac979b63fec7fa1ee0c47"),
        "name" : "phyger-2",
        "age" : 20
}
{
        "_id" : ObjectId("62bac98bb63fec7fa1ee0c48"),
        "name" : "phyger-1",
        "age" : 19,
        "home" : "china"
}
> db.test.update({"age":19},{$swt:{"name":"phyger-19"}})
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 0,
        "nModified" : 0,
        "writeError" : {
                "code" : 9,
                "errmsg" : "Unknown modifier: $swt"
        }
})
> db.test.update({"age":19},{$set:{"name":"phyger-19"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.test.find().pretty()
{
        "_id" : ObjectId("62bac83d6e89996fc64680e6"),
        "name" : "phyger-19",
        "age" : 19
}
{
        "_id" : ObjectId("62bac979b63fec7fa1ee0c47"),
        "name" : "phyger-2",
        "age" : 20
}
{
        "_id" : ObjectId("62bac98bb63fec7fa1ee0c48"),
        "name" : "phyger-1",
        "age" : 19,
        "home" : "china"
}
>

如上,可以看到,直接update只能更新第一条数据,怎么修改查询到的多个数据呢?

> db.test.find({"age":19}).pretty()
{
        "_id" : ObjectId("62bac83d6e89996fc64680e6"),
        "name" : "phyger-19",
        "age" : 19
}
{
        "_id" : ObjectId("62bac98bb63fec7fa1ee0c48"),
        "name" : "phyger-1",
        "age" : 19,
        "home" : "china"
}
> db.test.update({"age":19},{$set:{"name":"phyger-19a"}},{multi:true})
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })
> db.test.find({"age":19}).pretty()
{
        "_id" : ObjectId("62bac83d6e89996fc64680e6"),
        "name" : "phyger-19a",
        "age" : 19
}
{
        "_id" : ObjectId("62bac98bb63fec7fa1ee0c48"),
        "name" : "phyger-19a",
        "age" : 19,
        "home" : "china"
}
>

如上,在更新的时候加上{multi:true}参数,即可实现批量的修改。

upsert参数

如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入

> db.test.update({"age":19},{$set:{"name":"phyger-19a"}},{multi:true,upsert:1})
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("62bad325c008bae5b3cdce60")
})
> db.test.find().pretty()
{
        "_id" : ObjectId("62bac979b63fec7fa1ee0c47"),
        "name" : "phyger-2",
        "age" : 20
}
{ "_id" : ObjectId("62bad0b8b63fec7fa1ee0c4a"), "name" : "phyger-3" }
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
>

如上,使用{multi:true,upsert:1}参数后,,因为没有匹配到数据,无法更新,所以直接插入了数据,但是我们的update是$set:指定了参数name,没有指定age,但是更新插入后却将原有name为phyger-19a的整个对象恢复了出来(恢复的是最近的状态,比如一个对象被改了很多次然后删掉了,我们在update不存在的对象的时候指定upsert为1,query的对象匹配到了被删除的对象,则只会恢复被删除对象最后一次的数据)。

证明了:MongoDB的删除只是标记,实际未做删除,在下次更新插入的时候会将数据恢复。

2.3.4、删除数据

删除操作的语法格式:

db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>
   }
)
> db.test.remove({"age":19},{justOne:1})
WriteResult({ "nRemoved" : 1 })
> db.test.remove({"age":19},{justOne:1})
WriteResult({ "nRemoved" : 1 })
> db.test.remove({"age":19},{justOne:1})
WriteResult({ "nRemoved" : 0 })

如上,携带{justOne:1}参数,一次只删除一个,如果不带,则会一次全部删除匹配到的结果。

2.4、逻辑语句

2.4.1、AND

> db.test.find({"name":"phyger-2","age":18}).pretty()
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger-2",
        "age" : 18
}
>

以上,在query条件中多个,隔开的条件之间就是ADN关系。

2.4.2、OR

> db.test.find({$or:[{"name":"phyger-2"},{"age":19}]}).pretty()
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{ "_id" : ObjectId("62bad4ddc008bae5b3cdce85"), "name" : "phyger-2" }
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger-2",
        "age" : 18
}
{
        "_id" : ObjectId("62bad64cc008bae5b3cdce99"),
        "name" : "phyger-2",
        "age" : 19
}
>

如上,语句{$or:[{"name":"phyger-2"},{"age":19}]}中的{"name":"phyger-2"}{"age":19}之间的关系就是OR

2.5、条件语句

当我们想要根据某个字段的条件来进行查询的时候需要使用到MongoDB的条件语句。

  • (>) 大于 : $gt
  • (<) 小于 : $lt
  • (>=) 大于等于 : $gte
  • (<= ) 小于等于 : $lte
> db.test.find({age:{$gt:18}}).pretty()
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad64cc008bae5b3cdce99"),
        "name" : "phyger-2",
        "age" : 19
}
>
> db.test.find({age:{$gte:18}}).pretty()
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger-2",
        "age" : 18
}
{
        "_id" : ObjectId("62bad64cc008bae5b3cdce99"),
        "name" : "phyger-2",
        "age" : 19
}
>

以上为大于和大于等于,小于和小于等于类似。

3、高级功能

3.1、$type

用于获取指定字段的指定类型数据库。

比如我想获取,name字段全部为string的数据。

> db.test.find().pretty()
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
{
        "_id" : ObjectId("62bad64cc008bae5b3cdce99"),
        "name" : 321222,
        "age" : 19
}
> db.test.find({"name": {$type:"string"}}).pretty()   # 指定类型为:string
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
> db.test.find({"name": {$type:2}}).pretty()         # 指定类型为:2 相当于string
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
>

3.2、Limit和Skip

limit用于限制查询到的数据数量。

> db.test.find({"name": {$type:2}}).pretty()
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
> db.test.find({"name": {$type:2}}).pretty().limit(1)
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
>

skip一般用于和limit结合,用于跳过指定数量的数据。

> db.test.find({"name": {$type:2}}).pretty().limit(2)
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
> db.test.find({"name": {$type:2}}).pretty().limit(2).skip(1)
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
>

如上,limit出来的两条数据,使用skip(1)会跳过第一条。

3.3、排序

> db.test.find({"name": {$type:2}}).pretty()
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
>
> db.test.find({"name": {$type:2}}).pretty().sort({"age":1})
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
> db.test.find({"name": {$type:2}}).pretty().sort({"age":-1})
{
        "_id" : ObjectId("62bad325c008bae5b3cdce60"),
        "age" : 19,
        "name" : "phyger-19a"
}
{
        "_id" : ObjectId("62bad63fc008bae5b3cdce94"),
        "name" : "phyger",
        "age" : 18
}
>

如上,我们使用sort({"age":1}就可以根据age进行升序排序,使用sort({"age":-1}就可以根据age进行降序排序。

更多功能请移步官方文档中文版

1

评论区