先言之
☘️随着大数据时代的到来,非关系型数据库因其灵活性和扩展性逐渐受到开发者的青睐。MongoDB
和 Redis
作为两种非常流行的 NoSQL
数据库,各自拥有独特的特性和应用场景。MongoDB
是一款面向文档
的数据库,适用于需要存储复杂数据结构的应用;而 Redis
则以其卓越的速度和内存存储能力著称,非常适合高速缓存
和实时数据分析
。
✍️本文旨在为初学者提供一份简洁明了的手册,帮助大家快速掌握 MongoDB
和 Redis
的基本语法及常用操作。通过本指南的学习,读者将能够迅速上手这两种数据库,为实际项目开发奠定坚实的基础。
🤲本文内容均基于官方文档
撰写,并附带了相应的 SQL 语法链接。我希望在为大家提供正确语法规则的同时,也能鼓励大家养成查阅官方文档的好习惯!愿初学者以此为基础,不断探索,终成大家。
MongoDB 7.0
官网介绍:https://www.mongodb.com/zh-cn/docs/manual/
MongoDB 是一种非常流行的 NoSQL
数据库,特别适合那些需要处理大量非结构化或半结构化数据的应用程序。MongoDB 是一个文档数据库,为简化应用程序的开发与扩展而设计。MongoDB 中的记录是一个文档,它是由字段和值对组成的数据结构。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档、数组和文档数组。MongoDB 将文档存储在集合中。集合类似于关系数据库中的表。
图中展示的是MongoDB容器中的三个内置数据库及其对应的系统集合。让我们逐一介绍它们:
-
local 数据库:
local
数据库主要用于存储特定于单个MongoDB实例的数据。startup_log
是一个日志集合,记录了MongoDB服务器启动时的一些重要事件。 -
config 数据库:
config
数据库仅在分片集群中使用,用于存储分片集群的配置信息。system.sessions
存储跨多个分片的操作会话信息(自MongoDB 4.0开始引入)。 -
admin 数据库:admin数据库是一个特殊的“超级用户”数据库,用于执行管理任务,如运行权限检查、数据库查询等。它包含一个名为
system.users
的集合,其中存储着全局用户的认证信息。system.version
存储MongoDB版本信息(自MongoDB 4.2开始引入)。
🌕文档(Document)
☘️官方详细概念:https://www.mongodb.com/zh-cn/docs/manual/core/document/
MongoDB 将数据记录存储为 BSON
文档。BSON
是 JSON
文档的二进制表示形式,但它包含的数据类型比 JSON
多。
🌖文档结构
MongoDB 文档由字段
和值
对组成,具有以下结构:
{
field1: value1,
field2: value2,
field3: value3,
...
fieldN: valueN
}
字段值可以是任何一种 BSON 数据类型,包括其他文档、数组和文档数组。例如,以下文档包含不同类型的值:
var mydoc = {
_id: ObjectId("5099803df3f4948bd2f98391"),
name: { first: "Alan", last: "Turing" },
birth: new Date('Jun 23, 1912'),
death: new Date('Jun 07, 1954'),
contribs: [ "Turing machine", "Turing test", "Turingery" ],
views : NumberLong(1250000)
}
🌖QUERY / Find DOCUMENT
☘️详细语法:db.collection.find(query, projection, options)
db.collection.findOne(query, projection, options)
读取
操作用于从集合
中检索文档
,即查询
集合中的文档。
🌰:选择集合中的所有文档
-- 查询所有文档
db.inventory.find( {} )
-- 该操作使用 {} 的过滤谓词,对应以下 SQL 声明:
SELECT * FROM inventory
🌰:指定相等条件
-- 从 inventory 中选择集合所有 status 等于 "D" 的文档:
db.inventory.find( { status: "D" } )
-- 该操作使用 { status: "D" } 的过滤谓词,对应以下 SQL 声明:
SELECT * FROM inventory WHERE status = "D"
🌰:使用查询操作符指定条件
-- 从 inventory 集合中检索所有文档。其中 status 等于 "A" 或 "D":
db.inventory.find( { status: { $in: [ "A", "D" ] } } )
-- 该操作使用 { status: { $in: [ "A", "D" ] } } 的过滤谓词,对应以下 SQL 声明:
SELECT * FROM inventory WHERE status in ("A", "D")
🌰:指定 AND
条件。复合查询可以为集合文档中的多个字段指定条件。逻辑 AND 连接词隐式地连接复合查询的子句,以便该查询选择集合中与所有条件匹配的文档。
-- 检索 inventory 集合中 status 等于 "A" 且qty 小于 ($lt) 30 的所有文档:
db.inventory.find( { status: "A", qty: { $lt: 30 } } )
-- 该操作使用 { status: "A", qty: { $lt: 30 } } 的过滤谓词,对应以下 SQL 声明:
SELECT * FROM inventory WHERE status = "A" AND qty < 30
🌰:指定 OR
条件。可以使用 $or
操作符指定复合查询,该复合查询使用逻辑 OR
连接词连接每个每个子句,以便该查询选择集合中至少匹配一个条件的文档。
-- 检索集合中 status 等于 "A" 或 qty 小于 ($lt) 30 的所有文档:
db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )
-- 该操作使用 { $or: [ { status: 'A' }, { qty: { $lt: 30 } } ] } 的过滤谓词,对应以下 SQL 声明:
SELECT * FROM inventory WHERE status = "A" OR qty < 30
🌰:指定 AND
和 OR
条件
-- 复合查询文档选择集合中 status 等于 "A" 小于 ( 且 ) 以字符 30 开头的文档:$ltitem 或 p
db.inventory.find( {
status: "A",
$or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]
} )
-- 对应如下 SQL 语句:
SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")
🌰:使用空查询规范。虽然与 find()
方法类似,但 findOne()
方法返回的是文档而不是游标。
db.bios.findOne()
🌰:返回 BIOS
集合中的第一个匹配文档,其中嵌入式文档 name 中的字段 first 以字母 G 开头,或者字段 birth 小于 new Date(‘01/01/1945’):
db.bios.findOne(
{
$or: [
{ 'name.first' : /^G/ },
{ birth: { $lt: new Date('01/01/1945') } }
]
}
)
🌰:返回 BIOS
集合中的文档(contribs 字段包含元素 OOP),并返回除 之外的 字段、_id 嵌入式文档中的 name 字段和 first birth所有字段:
db.bios.findOne(
{ contribs: 'OOP' },
{ _id: 0, 'name.first': 0, birth: 0 }
)
🌗CREATE / Insert DOCUMENT
☘️详细语法:https://www.mongodb.com/zh-cn/docs/manual/tutorial/insert-documents/
创建
或插入
操作用于将新文档
添加到集合
中。 如果集合
当前不存在,插入操作会创建集合
。在 MongoDB 中,存储在集合中的每个文档都需要一个唯一的 _id
字段作为主键。如果插入的文档省略了 _id
字段,MongoDB 驱动程序会自动为 ObjectId
字段生成一个 _id
。
🌰:Collection.insertOne()
将单个文档插入到集合中。
-- 将新文档插入 `inventory` 集合。
db.inventory.insertOne(
{ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
-- 要检索刚刚插入的文档,请查询该集合:
db.inventory.find( { item: "canvas" } )
🌰:db.collection.insertMany()
可以将多个文档插入到一个集合中。
-- 将三个新文档插入inventory集合。
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
{ item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
{ item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
-- 要检索插入的文档,请查询集合
db.inventory.find( {} )
🌰(高深):bios
集合提供了用于 MongoDB
实验的示例数据。
https://www.mongodb.com/zh-cn/docs/manual/reference/bios-example-collection/#std-label-bios-example-collection
db.bios.insertMany([
{
"_id" : 1,
"name" : {
"first" : "John",
"last" : "Backus"
},
"birth" : ISODate("1924-12-03T05:00:00Z"),
"death" : ISODate("2007-03-17T04:00:00Z"),
"contribs" : [
"Fortran",
"ALGOL",
"Backus-Naur Form",
"FP"
],
......
{
"_id" : 10,
"name" : {
"first" : "Martin",
"last" : "Odersky"
},
"contribs" : [
"Scala"
]
}
] )
🌘UPDATE DOCUMENT
☘️详细语法:https://www.mongodb.com/zh-cn/docs/manual/tutorial/update-documents/
更新
操作用于修改集合
中的现有文档 。
🌰:使用 db.collection.updateOne()
集合上的 inventory
方法来更新 第一个 等于 item 的"paper"
文档:
db.inventory.updateOne(
{ item: "paper" },
{
$set: { "size.uom": "cm", status: "P" },
$currentDate: { lastModified: true }
}
)
🌰:使用 db.collection.updateMany()
集合上的 inventory
方法更新 qty 小于 50
的所有文档:
db.inventory.updateMany(
{ "qty": { $lt: 50 } },
{
$set: { "size.uom": "in", status: "P" },
$currentDate: { lastModified: true }
}
)
🌰:替换除 _id
字段之外的文档的所有内容,请将全新文档作为第二个参数传递给 db.collection.replaceOne()
db.inventory.replaceOne(
{ item: "paper" },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)
🌑DELETE DOCUMENT
☘️详细语法:https://www.mongodb.com/zh-cn/docs/manual/tutorial/remove-documents/
删除
操作用于从集合
中删除文档。
🌰:要删除集合中的所有文档,请将空的过滤器文档 {} 传递给 db.collection.deleteMany()
方法。
-- 删除 所有 集合中的inventory文档:
db.inventory.deleteMany({})
🌰:指定条件或过滤器来标识要删除的文档。
-- 从 status 字段等于 "A" 的 inventory 集合中删除所有文档:
db.inventory.deleteMany({ status : "A" })
🌰:要删除最多一个与指定的筛选器匹配的文档(即使指定的筛选器可能存在多个匹配的文档),请使用 db.collection.deleteOne()
方法。
-- 删除 第一个 为 `status 的"D"`文档:
db.inventory.deleteOne( { status: "D" } )
更多方法:https://www.mongodb.com/zh-cn/docs/manual/reference/method/
Redis
官网介绍:https://redis.io/docs/latest/?spm=5176.28103460.0.0.297c572cWOYo4Z
Redis (Remote Dictionary Server)
是一个开源的、高性能的、基于内存的数据结构存储系统。它不仅仅是一个简单的键值存储系统,还支持多种数据结构,如字符串(String)
、哈希(Hash)
、列表(List)
、集合(Set)
、有序集合(Zset)
等。这些数据结构使得 Redis 成为一个非常灵活的工具,可以用于多种场景,如缓存、消息队列、实时分析等。
🌕字符串(String)
🌖SET key value
☘️详细语法:https://redis.io/docs/latest/commands/set/
设置键 key
的值为 value
。
🌰:
-- 创建一个键 mykey,并将其值设置为 "Hello"。
-- 如果 mykey 已经存在,那么这个命令会更新 mykey 的值为 "Hello"。
SET mykey "Hello"
-- 在 Redis 中创建一个键 anotherkey,并将其值设为 "will expire in a minute"
-- 同时设置这个键的过期时间为 60 秒。60 秒后,这个键将自动从 Redis 中删除。
SET anotherkey "will expire in a minute" EX 60
🌗GET key
☘️详细语法:https://redis.io/docs/latest/commands/get/
获取键 key
的值。
🌰:
-- 如果 mykey 存在,Redis 会返回其对应的值。
-- 如果 mykey 不存在,Redis 会返回 nil(空值)。
GET mykey
🌘INCR key
☘️详细语法:https://redis.io/docs/latest/commands/incr/
将键 key
的值增 1,如果键不存在,则先初始化为 0 再增 1。
🌰:
redis> SET mykey "10"
"OK"
redis> INCR mykey
(integer) 11
redis> GET mykey
"11"
🌑DECR key
☘️详细语法:https://redis.io/docs/latest/commands/decr/
将键 key
的值减 1,如果键不存在,则先初始化为 0 再减 1。
🌰:
redis> SET mykey "10"
"OK"
redis> DECR mykey
(integer) 9
redis> SET mykey "234293482390480948029348230948"
"OK"
redis> DECR mykey
(error) value is not an integer or out of range
🌕哈希(Hash)
🌖HSET key field value
☘️详细语法:https://redis.io/docs/latest/commands/hset/
将哈希表 key
中的字段 field
的值设为 value
。
🌰:
redis> HSET myhash field1 "Hello"
"OK"
redis> HGET myhash field1
"Hello"
redis> HSET myhash field2 "Hi" field3 "World"
"OK"
redis> HGET myhash field2
"Hi"
redis> HGET myhash field3
"World"
redis> HGETALL myhash
(如下图)
🌗HGET key field
☘️详细语法:https://redis.io/docs/latest/commands/hget/
获取哈希表 key
中字段 field
的值。
🌰:
redis> HSET myhash field1 "foo"
(integer) 1
redis> HGET myhash field1
"foo"
redis> HGET myhash field2
(nil)
🌘HGETALL key
☘️详细语法:https://redis.io/docs/latest/commands/hgetall/
获取哈希表 key
中所有字段和值。
🌰:
redis> HSET myhash field1 "Hello"
(integer) 0
redis> HSET myhash field2 "World"
(integer) 0
redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"
🌕列表(List)
🌖LPUSH key value
☘️详细语法:https://redis.io/docs/latest/commands/lpush/
将一个或多个值 value
插入到列表 key
的表头。
🌰:
redis> LPUSH mylist "world"
(integer) 1
redis> LPUSH mylist "hello"
(integer) 2
redis> LRANGE mylist 0 -1
1) "hello"
2) "world"
🌗RPUSH key value
☘️详细语法:https://redis.io/docs/latest/commands/rpush/
将一个或多个值 value
插入到列表 key
的表尾。
🌰:
redis> RPUSH mylist "hello"
(integer) 3
redis> RPUSH mylist "world"
(integer) 4
redis> LRANGE mylist 0 -1
(如下图,先前已经LPUSH了,所以4个数据)
🌘LPOP key
☘️详细语法:https://redis.io/docs/latest/commands/lpop/
移除并获取列表 key
的第一个元素。
🌰:
redis> RPUSH mylist "one" "two" "three" "four" "five"
(integer) 9
redis> LPOP mylist
"hello"
redis> LPOP mylist 2
1)world
2)hello
redis> LRANGE mylist 0 -1
(如下图)
🌑RPOP key
☘️详细语法:https://redis.io/docs/latest/commands/rpop/
移除并获取列表 key
的最后一个元素。
🌰:
redis> RPUSH mylist "one" "two" "three" "four" "five"
(integer) 5
redis> RPOP mylist
"five"
redis> RPOP mylist 2
1) "four"
2) "three"
redis> LRANGE mylist 0 -1
1) "one"
2) "two"
🌑LRANGE key start stop
☘️详细语法:https://redis.io/docs/latest/commands/lrange/
获取列表 key
中指定范围的元素。
🌰:
redis> RPUSH mylist "one"
(integer) 1
redis> RPUSH mylist "two"
(integer) 2
redis> RPUSH mylist "three"
(integer) 3
redis> LRANGE mylist 0 0
1) "one"
redis> LRANGE mylist -3 2
1) "one"
2) "two"
3) "three"
redis> LRANGE mylist -100 100
1) "one"
2) "two"
3) "three"
redis> LRANGE mylist 5 10
(empty array)
🌕集合(Set)
🌖SADD key member
☘️详细语法:https://redis.io/docs/latest/commands/sadd/
将一个成员 member
添加到集合 key
中。
🌰:
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "Hello"
2) "World"
🌗SMEMBERS key
☘️详细语法:https://redis.io/docs/latest/commands/smembers/
获取集合 key
中的所有成员。
🌰:
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SMEMBERS myset
1) "Hello"
2) "World"
🌘SREM key member
☘️详细语法:https://redis.io/docs/latest/commands/srem/
从集合 key
中移除一个成员 member
。
🌰:
redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myset "three"
(integer) 1
redis> SREM myset "one"
(integer) 1
redis> SREM myset "four"
(integer) 0
redis> SMEMBERS myset
1) "two"
2) "three"
🌑SCARD key
☘️详细语法:https://redis.io/docs/latest/commands/scard/
获取集合 key
的基数(即成员数量)。
🌰:
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SCARD myset
(integer) 2
🌕有序集合(Zset)
🌖ZADD key score member
☘️详细语法:https://redis.io/docs/latest/commands/zadd/
将一个成员 member
添加到有序集合 key
中,并为其设置一个分数 score
。
🌰:
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 1 "uno"
(integer) 1
redis> ZADD myzset 2 "two" 3 "three"
(integer) 2
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
🌗ZRANGE key start stop [WITHSCORES]
☘️详细语法:https://redis.io/docs/latest/commands/zrange/
获取有序集合 key
中指定范围的成员,可选参数 [WITHSCORES]
表示同时获取分数。
🌰:
redis> ZADD myzset 1 "one" 2 "two" 3 "three"
(integer) 3
redis> ZRANGE myzset 0 -1
1) "one"
2) "two"
3) "three"
redis> ZRANGE myzset 2 3
1) "three"
redis> ZRANGE myzset -2 -1
1) "two"
2) "three"
🌰:此示例显示如何按分数查询排序集,不包括值1并直到无穷大,仅返回结果的第二个元素。
redis> ZADD myzset 1 "one" 2 "two" 3 "three"
(integer) 3
redis> ZRANGE myzset (1 +inf BYSCORE LIMIT 1 1
1) "three"
🌘ZREM key member
☘️详细语法:https://redis.io/docs/latest/commands/zrem/
从有序集合 key
中移除一个成员 member
。
🌰:
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREM myzset "two"
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "three"
4) "3"
🌑ZCARD key
☘️详细语法:https://redis.io/docs/latest/commands/zcard/
获取有序集合 key
的基数(即成员数量)。
🌰:
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZCARD myzset
(integer) 2
🌕其他
🌖DEL key
☘️详细语法: https://redis.io/docs/latest/commands/del/
删除一个或多个键。
🌰:
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> DEL key1 key2 key3
(integer) 2
🌗EXISTS key
☘️详细语法:https://redis.io/docs/latest/commands/exists/
检查给定的键是否存在。
🌰:
redis> SET key1 "Hello"
"OK"
redis> EXISTS key1
(integer) 1
redis> EXISTS nosuchkey
(integer) 0
redis> SET key2 "World"
"OK"
redis> EXISTS key1 key2 nosuchkey
(integer) 2
🌘KEYS pattern
☘️详细语法:https://redis.io/docs/latest/commands/keys/
查找所有匹配给定模式的键。
🌰:
-- MSET同时设置一个或多个键值对。
redis> MSET firstname Jack lastname Stuntman age 35
"OK"
redis> KEYS *name*
1) "lastname"
2) "firstname"
redis> KEYS a??
1) "age"
redis> KEYS *
1) "lastname"
2) "firstname"
3) "age"
🌑EXPIRE key seconds
☘️详细语法:https://redis.io/docs/latest/commands/expire/
设置键 key 的生存时间(以秒为单位)。
🌰:
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> SET mykey "Hello World"
"OK"
redis> TTL mykey
(integer) -1
-- XX — 仅当密钥已有到期时间时才设置到期时间
-- GT — 仅当新到期时间大于当前到期时间时才设置到期时间
-- LT — 仅当新到期时间小于当前到期时间时才设置到期时间
redis> EXPIRE mykey 10 XX
(integer) 0
redis> TTL mykey
(integer) -1
-- NX — 仅当密钥没有到期时才设置到期时间
redis> EXPIRE mykey 10 NX
(integer) 1
redis> TTL mykey
(integer) 10
当然了除了这些命令,还有很多常用的命令:SAVE
、BGSAVE
、LASTSAVE
、TTL key
等等。
更多命令:https://redis.io/docs/latest/commands/
综括而言
👋通过本文的学习,我们不仅了解了 MongoDB
和 Redis
的基本概念,还掌握了它们的核心功能和操作方法。MongoDB
作为一种面向文档的数据库,提供了灵活的数据模型和强大的查询语言,适用于存储复杂的数据结构。Redis
则以其超高的性能和丰富的数据结构,成为了构建高性能应用和服务的理想选择。
🌈无论是需要处理大量文档数据还是寻求高速缓存解决方案,MongoDB
和 Redis
都能提供有效的支持。希望读者能够通过本篇文章获得足够的知识基础,进一步探索这两种数据库的高级特性,并将其应用到实际工作中,提升应用的性能和稳定性。未来,随着对这些技术的深入理解,你将能够更好地利用它们的优势来解决实际问题。