文档是MongoDB中的基本数据单元,相当于传统关系型数据库中的行,它是一组有序键值的集合。每个文档都有子一个特殊的键“_id”,其在所属的集合中是唯一的。
文档中的键是字符串类型。
键中不能含有\0(空字符)。这个字符用于表示一个键的结束。
.和$是特殊字符,只能在某些特定情况下使用。通常情况下,可以认为这两个字符是MongoDB的保留字符,如果使用不当,那么驱动程序将无法正常工作。
集合就是一组文档。可以看做是具有动态模式的表。
集合具有动态模式的特性。这意味着一个集合中的文档可以具有任意数量的不同形态。
但是,将不同类型的文档存放在一个集合中会出现很多问题:
\0
(空字符),因为这个字符用于表示一个集合名称的结束;system.
开头,该前缀是为内部集合保留的。MongoDB使用集合对文档进行分组,使用数据库对集合进行分组。通常情况下,一个应用程序对应一个数据库,一个数据库包含多个集合,一个集合包含多个文档。
MongoDB中的文档可以被认为是“类似于JSON”的形式,JSON是一种简单的数据表示形式,只有6种数据类型
MongoDB在保留了JSON基本键值对特性的基础上,增加了许多额外的数据类型,最常见的如下:
_id
ObjectId是“_id”
的默认类型。ObjectId类采用了轻量化设计,可以很容易地在不同的机器上以全局唯一的方式生成。MongoDB的分布式特性是它使用ObjectId而不是使用自增主键的主要原因,跨多个服务器同步自增主键既困难又耗时。因为MongoDB的设计初衷就是作为一个分布式数据库,所以能够在分片环境中生成唯一的标识符非常重要。
ObjectId占用了12字节的存储空间,可以用24个十六进制数字组成的字符串来表示,每字节存储两个数字。
ObjectId的12字节是按照如下方式生成的:
ObjectId的前4个字节是从Unix纪元开始以秒为单位的时间戳。时间戳与随后的5个字节组合在一起,在秒级别的粒度上提供了唯一性。
MongoDB自带一个简单但功能强大的工具:mongo shell。mongo shell对管理MongoDB实例和使用MongoDB的查询语言操作数据提供了内置的支持。它也是一个功能齐全的JavaScript解释器,用户可以根据需求创建或加载自己的脚本。
$set
用来设置一个字段的值。如果这个字段不存在,则创建该字段。
对于更新操作或添加操作非常方便。
$unset
表示删除这个键。
$inc
运算符可以用来修饰已存在的键值或者在该键不存在时创建它。对于更新分析数据、因果关系、投票或者其他有数值变化的地方,使用这个会非常方便。
数组是常见的功能强大的数据结构,它不仅可以通过索引进行引用的列表,而且可以作为集合来使用。
如果数组已存在,$push
就会将元素添加到数组末尾;如果数组不存在,则会创建一个新的数组。可以对$push
使用$each
修饰符,再一次操作中添加多个值。
> db.nezha.updateOne({"id":"1"},{"$push":{"job":[1,2,3]}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.nezha.find()
{ "_id" : ObjectId("638b1273bb535f1c23f9b096"), "id" : "1", "name" : "哪吒编程", "job" : [ [ 1, 2, 3 ] ] }
>
再次updateOne时,还是会增加:
> db.nezha.updateOne({"id":"1"},{"$push":{"job":[1,2,3]}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.nezha.find()
{ "_id" : ObjectId("638b1273bb535f1c23f9b096"), "id" : "1", "name" : "哪吒编程", "job" : [ [ 1, 2, 3 ], [ 1, 2, 3 ] ] }
>
仅当一个值不存在时菜进行添加,可以在查询文档的时候使用``“$ne”```来实现:
> db.nezha.updateOne({"id":{"$ne":"1"}},{"$push":{"job":[1,2,3]}})
{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 }
> db.nezha.find()
{ "_id" : ObjectId("638b1273bb535f1c23f9b096"), "id" : "1", "name" : "哪吒编程", "job" : [ [ 1, 2, 3 ], [ 1, 2, 3 ] ] }
也可以使用"$addToSet"
来避免插入重复的值,还可以通过"$addToSet"
与$each
结合使用,添加多个不同的值。
> db.nezha.updateOne({"id":"1"},{"$addToSet":{"address":"辽宁省大连市高新园区"}}))
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
> db.nezha.find() 园区"}}})
{ "_id" : ObjectId("638b1273bb535f1c23f9b096"), "id" : "1", "name" : "哪吒编程", "job" : [ [ 1, 2, 3 ], [ 1, 2, 3 ] ], "address" : [ "辽宁省大连市高新园区"] }
有多种方法可以从数组中删除元素。
如果将数组视为队列或者栈,那么可以使用"$pop"从任意一端删除元素。
> db.workers.insert({id:'1',name:['哪吒编程','云韵','萧炎']})
WriteResult({ "nInserted" : 1 })
> db.workers.find()
{ "_id" : ObjectId("638b2154bb535f1c23f9b098"), "id" : "1", "name" : [ "哪吒编程", "云韵", "萧炎" ] }
>
萧炎实在是太碍事了,删掉他。
> db.workers.find()
{ "_id" : ObjectId("638b2154bb535f1c23f9b098"), "id" : "1", "name" : [ "哪吒编程", "云韵", "萧炎" ] }
> db.workers.updateOne({},{"$pull":{"name":"萧炎"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.workers.find()
{ "_id" : ObjectId("638b2154bb535f1c23f9b098"), "id" : "1", "name" : [ "哪吒编程", "云韵" ] }
修改数组中特定的值,可以按位置或使用定位运算符$。
> db.users.insert({id:'1',dept:[
... {"name":"哪吒编程","age":18,"address":"大连"},
... {"name":"云韵","age":19,"address":"大连"},
... {"name":"萧炎","age":28,"address":"北京"}]})
WriteResult({ "nInserted" : 1 })
> db.users.find() ss":"北京"}]})
{ "_id" : ObjectId("638b2605bb535f1c23f9b099"), "id" : "1", "dept" : [ { "name" : "哪吒编程", "age" : 18, "address" : "大连" }, { "name" : "云韵", "age" : 19, "address" : "大连" }, { "name" : "萧炎", "age" : 28, "address" : "北京" } ] }
>
想要将文档中的萧炎修改为美杜莎,怎么修改呢?
> db.users.updateOne({"dept.name":"萧炎"},{"$set":{"dept.$.name":"美杜莎"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find() "}})
{ "_id" : ObjectId("638b2822bb535f1c23f9b09a"), "id" : "1", "dept" : [ { "name" : "哪吒编程", "age" : 18, "address" : "大连" }, { "name" : "云韵", "age" : 19, "address" : "大连" }, { "name" : "美杜莎", "age" : 28, "address" : "北京" } ] }
>
MongoDB 3.6 引入了用于更新单个数组元素的选项:arrayFilters
。此选项使我们能够修改特定条件匹配的数组元素。
upsert是一种特殊类型的更新,如果找不到与筛选条件相匹配的文档,则会以这个条件和更新文档为基础来创建一个新文档;如果找到了匹配的文档,则进行正常的更新。upsert用起来非常方便,有了它便不再需要创建集合,通常可以使用同一套代码创建和更新文档。
save是一个shell函数,它可以在文档不存在时插入文档,在文档存在时更新文档。它只将一个文档作为其唯一的参数。如果文档中包含"_id"键,save就会执行一个upsert。否则,将执行插入操作。save实际上只是一个为了方便而使用的函数。
NoSQL数据库进阶实战1,那些年学过的NoSQL基础
NoSQL数据库进阶实战2,NoSQL数据存储模式
Redis缓存穿透、击穿、雪崩到底是个啥?7张图告诉你
Redis分布式锁的实现方式
Redis分布式缓存、秒杀
基于Stream的Redis消息队列
Java学习路线总结,搬砖工逆袭Java架构师
10万字208道Java经典面试题总结(附答案)
Java基础教程系列
Java高并发编程系列
数据库进阶实战系列