mongodb知识点整理

文章目录

  • 一、 安装
    • 1、Windows安装配置
    • 2、服务器端启动
  • 二、基本术语和概念
    • 1、下表介绍了各种SQL和MongoDB对比的术语和概念
    • 2、下表是部分数据库与MongoDB可运行程序名称的对比
    • 3、MongoDB保留的数据库名称
    • 4、数据类型
  • 三、MongoDB shell
    • 1、连接服务器
    • 2、使用帮助
    • 3、执行基本的Javascript
      • 3.1、执行基本的数学运算
      • 3.2、使用JavaScript 标准库
      • 3.3、使用JavaScript 函数
      • 3.4、打印函数源代码
      • 3.5、执行JavaScript文件
      • 3.6、用load 函数先加载,再从交互式shell中运行脚本
      • 3.7、shell辅助函数对应的JavaScript函数
      • 3.8、可以定义函数变量,例如defineConnectTo.js
  • 四、创建、更新和删除文档
    • 1、插入文档
    • 2、删除文档
    • 3、更新文档
  • 五、查询
    • 1、find和findOne
    • 2、查询条件
      • 2.1、查询条件
      • 2.2、OR查询
      • 2.3、$not
    • 3、特定类型的查询
      • 3.1、null
      • 3.2、正则表达式
      • 3.3、查询数组
      • 3.4、查询内嵌文档
    • 4、$where查询
    • 5、游标
  • 六、索引
    • 1、索引操作
      • 1.1、创建索引
      • 1.2、查询语句中加上explain,检查索引是否命中
      • 1.3、优化策略
  • 七、特殊的索引和集合类型
    • 1、地理空间索引
      • 1.1、Legacy Coordinate Pairs格式
      • 1.2、GeoJSON格式
      • 1.3、地理空间查询
        • 1.3.1、根据坐标查找所处街区
        • 1.3.2、查找区域内所有人
        • 1.3.3、返回指定距离内的人(无序)
    • 2、全文搜索索引
    • 3、固定集合
    • 4、TTL索引
    • 5、使用GridFS存储文件

一、 安装

下载地址:https://www.mongodb.com/try/download/community

1、Windows安装配置

下载:mongodb-windows-x86_64-4.4.12.zip
解压:D:\penngo\mongodb-4.4.12
新建文件夹data,
D:\penngo\mongodb-4.4.12\data
新建配置文件
D:\penngo\mongodb-4.4.12\mongo.conf

# 数据库文件路径
dbpath=D:\penngo\mongodb-4.4.12\data
# 日志文件
logpath=D:\penngo\mongodb-4.4.12\mongo.log
# 日志采用追加模式,配置后mongodb日志会追加到现有的日志文件
#logappend=true
# 端口号 默认为 27017
port=27017
#指定mongodb使用内存的多少4G
#storage.wiredTiger.engineConfig.cacheSizeGB=4

启动命令

mongod --config ../mongo.conf

作为windows服务启动

mongod --config "D:\penngo\mongodb-4.4.12\mongo.conf" --install --serviceName "MongoDB"

2、服务器端启动

Unix 命令行:

$ mongod

Windows 命令行:

> mongod.exe

如果省略参数, mongod默认的使用数/data/db/(Windows为当前盘的 \data\db\)。因此在启动之前,需要创建数据目录(如 mkdir -p /data/db/),并且对该目录有写权限。

二、基本术语和概念

1、下表介绍了各种SQL和MongoDB对比的术语和概念

SQL术语/概念 MongoDB 术语/概念
数据库(database) 数据库(database)
表(table) 集合(collection)
行(row) 文档(document or BSON document)
列(column) 字段(field)
索引(index) 索引(index)
表连接(table joins) 多表关联,内嵌文档($lookup, embedded documents)
主键(primary key) 可以指定一列或多列作为主键 主键(primary key)
MongoDB默认以 _id字段为主键.
聚合,列如group by(aggregation (e.g. group by)) 聚合管道(aggregation pipeline)See the SQL to Aggregation Mapping Chart.
将一个表中的数据插入到另一个表(SELECT INTO NEW_TABLE) $out操作
查看 SQL to Aggregation Mapping Chart.
合并更新(MERGE INTO TABLE) $merge (MongoDB 4.2可用)
查看 SQL to Aggregation Mapping Chart.
合并查询(UNION ALL) $unionWith ( MongoDB 4.4可用)
事务(transactions) 事务(transactions)
注意:在许多场景下,应该使用合适的建模(例如内嵌文档或数组)来减少多文档事务的需求。

2、下表是部分数据库与MongoDB可运行程序名称的对比

MongoDB MySQL Oracle Informix DB2
服务器端程序 mongod mysqld oracle IDS DB2
客户端程序 mongosh mysql sqlplus DB-Access DB2 Client

3、MongoDB保留的数据库名称

admin:数据库会在身份验证和授权时被使用,某些管理操作也需要访问此数据库。
local:在副本集中,local 用于存储复制过程中所使用的数据,而 local 数据库本身不会被复制。
config:在分片集群会使用config数据库存储每个分片的信息。

4、数据类型

JSON数据格式支持有6 种数据类型,MongoDB 在JSON的基础上,增加了其它数据类型的支持。
null
null 类型用于表示空值或不存在的字段。
布尔类型
布尔类型的值可以为 true 或者 false。
数值类型
shell 默认使用 64 位的浮点数来表示数值类型。
{“x” : 3.14}
{“x” : 3}
对于整数,可以使用 NumberInt 或 NumberLong 类,它们分别表示 4 字节和 8 字节的有符号整数。
{“x” : NumberInt(“3”)}
{“x” : NumberLong(“3”)}
字符串类型
任何 UTF-8 字符串都可以使用字符串类型来表示。
{“x” : “foobar”}
日期类型
MongoDB 会将日期存储为 64 位整数,表示自 Unix 纪元(1970年 1 月 1 日)以来的毫秒数,不包含时区信息。
{“x” : new Date()}
正则表达式
查询时可以使用正则表达式,语法与 JavaScript 的正则表达式语法相同。
{“x” : /foobar/i}
数组类型
集合或者列表可以表示为数组。
{“x” : [“a”, “b”, “c”]}
内嵌文档
文档可以嵌套其他文档,此时被嵌套的文档就成了父文档的值。
{“x” : {“foo” : “bar”}}
Object ID
Object ID 是一个 12 字节的 ID,是文档的唯一标识。
{“x” : ObjectId()}
二进制数据
二进制数据是任意长度的字符串,不能通过 shell 操作。如果要将非 UTF-8 字符串存入数据库,那么使用二进制数据是唯一的方法。
代码
可以在查询和文档中存储任意的 JavaScript 代码:
{“x” : function() { /* … */ }}

三、MongoDB shell

mongo shell 是一个管理 MongoDB 实例和操作数据的命令行工具,同时是一个功能齐全的 JavaScript 解释器,能够运行任意的JavaScript 程序。

1、连接服务器

连接mongod服务器,需要指定主机名、端口和数据库,如果缺少这三个参数,默认连接本机服务器:

$ mongo host:27017/myDB

使用 --nodb 参数,不连接数据库:

$ mongo –nodb

可以在启动之后,再连接到mongod:

> conn = new Mongo("some-host:30000")
connection to some-host:30000
> db = conn.getDB("myDB")
myDB

2、使用帮助

内置了帮助文档,可以输入 help 命令查看:

> help
db.help() 查看数据库级别的帮助信息.
db.foo.help() 查看集合级别的帮助信息。

3、执行基本的Javascript

3.1、执行基本的数学运算

> x = 200;
> x / 5;

3.2、使用JavaScript 标准库

> Math.sin(Math.PI / 2);
> new Date("2019/1/1");
> "Hello, World!".replace("World", "MongoDB");

3.3、使用JavaScript 函数

> function factorial (n) {
... if (n <= 1) return 1;
... return n * factorial(n - 1);
... }
> factorial(5);
120

3.4、打印函数源代码

> db.movies.updateOne

3.5、执行JavaScript文件

 $ mongo script1.js script2.js

如果需要在远程主机运行脚本,则需要先指定地址,之后再指定脚本:

$ mongo server-1:30000/foo --quiet script1.js script2.js

3.6、用load 函数先加载,再从交互式shell中运行脚本

> load("script1.js")
I am script1.js
true
>

3.7、shell辅助函数对应的JavaScript函数

辅助函数 等价函数
use video db.getSisterDB(“video”)
show dbs db.getMongo().getDBs()
show collections db.getCollectionNames()

3.8、可以定义函数变量,例如defineConnectTo.js

var connectTo = function(port, dbname) {
 if (!port) {
 port = 27017;
 }
 if (!dbname) {
 dbname = "test";
 }
 db = connect("localhost:"+port+"/"+dbname);
 return db;
};

在shell 中加载defineConnectTo.js,connectTo 函数就可以使用了:

> load('defineConnectTo.js')
> typeof connectTo
function

四、创建、更新和删除文档

1、插入文档

insertOne 插入单个文档,文档自动添加一个 “_id” 键:

> db.movies.insertOne({"title" : "Stand by Me"})

insertMany插入多个文档

db.movies.insertMany([{"title" : "Ghostbusters"},{"title" : "E.T."}]);

insertMany批量插入文档会明显提高插入的速度。
从3.2 开始, shell 支持insertOne 和 insertMany 以及其他一些方法。insert 等方法仍然向后兼容,但不建议继续使用。

2、删除文档

deleteOne 将删除满足条件的第一个文档。
deleteMany 来删除满足筛选条件的所有文档。
drop清空整个集合,使用 drop 直接删除集合,然后在这个空集合中重建各项索引会更快:

> db.movies.drop()

从3.2 开始,shell支持deleteOne 和deleteMany这些方法。remove 仍可使用,但不推荐。

3、更新文档

updateOne、updateMany 和 replaceOne。
replaceOne 会用新文档完全替换匹配的文档。

“$set” 设置字段的值。

db.users.updateOne({"name" : "joe"},{"$set" : {"favorite book" :["Cat's Cradle", "Foundation Trilogy"]}})

“$unset” 删除字段:

db.users.updateOne({"name" : "joe"},{"$unset" : {"favorite book" : 1}})

“$inc” 自增和自减,只能用于整型、长整型或双精度浮点型:

db.users.updateOne({"game" : "pinball", "user" : "joe"}, {"$inc" : {"score" : 50}})

“$push” 给数组添加元素,默认添加在尾部,不存在则创建新的数组

db.blog.posts.updateOne({"title" : "A blog post"},{"$push" : {"comments" :{"name" : "joe", "email" : "[email protected]", "content" : "nice post."}}})

“$each” 可以对 “$push” 使用"$each" 修饰符,在一次操作中添加多个值:

db.stock.updateOne({"_id" : "GOOG"}, {"$push" : {"hourly" : {"$each" : [562.776, 562.790,559.123]}}})

“$slice” 配合 $push 设置数组长度:

db.movies.updateOne({"genre" : "horror"},{"$push" : {"top10" : {"$each" : ["hell1", "hell2",...],"$slice" : -10}}})

这个例子限制了数组只包含最后加入的 10 个元素。
“$sort” 可以将 “$sort” 修饰符应用于 “$push” 操作:

> db.movies.updateOne({"genre" : "horror"},{"$push" : {"top10" : {"$each" : [{"name" : "hello1","rating" : 6.6},{"name" : "hello2","rating" : 4.3},...], "$slice" : -10, "$sort" : {"rating" : -1}}}})

根据 “rating"值对数组中进行排序,只保留前 10 个。注意,不能只将 “$slice” 或”$sort" 与 “$push” 配合使用,必须包含 “$each”。
“$ne”“$addToSet” :将数组作为集合使用,仅当一个值不存在时才进行添加。

 > db.book.updateOne({"authors cited" : {"$ne" :"Richie"}},{$push : {"authors cited" : "Richie"}})
 >db.users.updateOne({"_id" :ObjectId("4b2d75476cc613d5ee930164")},{"$addToSet" : {"emails" : "[email protected]"}})

还可以将 “$addToSet”“$each” 结合使用,以添加多个不同的值,而这不能使用 “$ne”“$push” 的组合来实现。

 >db.users.updateOne({"_id" :ObjectId("4b2d75476cc613d5ee930164")},{"$addToSet" : {"emails" : {"$each" :["[email protected]","[email protected]","[email protected]"]}}})

“$pop” 删除元素。。

{"\$pop" : {"key" : 1}} 从尾部删除一个元素,
{"\$pop" : {"key" : -1}}从头部删除一个元素。

“$pull” 删除符合条件的所有数组元素。

> db.lists.updateOne({}, {"$pull" : {"todo" : "laundry"}})

“$” 定位运算符,它可以计算出查询文档匹配的数组元素并更新该元素。

> db.blog.updateOne({"comments.author" : "John"}, {"$set" : {"comments.$.author" : "Jim"}})

“arrayFilters”:此选项使我们能够修改与特定条件匹配的数组元素。

db.blog.updateOne({"post" : post_id },{ $set: { "comments.$[elem].hidden" : true } },{arrayFilters: [ { "elem.votes": { $lte: -5 } }]})

**“upsert”**如果找不到,则创建一个新文档;如果找到了匹配的文档,则进行正常的更新。

> db.analytics.updateOne({"url" : "/blog"}, {"$inc" :{"pageviews" : 1}},{"upsert" : true})

“save” shell 函数
在文档不存在时插入文档,在文档存在时更新文档。

> var x = db.score.findOne()
> x.num = 42
42
> db.score.save(x)

updateManyupdateOne接受相同的参数,区别在于被更改的文档数量。

> db.users.updateMany({"birthday" : "10/13/1978"}, {"$set" : {"gift" : "Happy Birthday!"}})

3.2 版本中 shell 引入了 3 个新的集合方法来提供findAndModify 的功能:findOneAndDeletefindOneAndReplacefindOneAndUpdate。与 updateOne 的区别在于,可以返回修改后的值。
findOneAndUpdate:4.2增加用来更新的聚合管道。管道可以包含以下操作:$addFields 及其别名 (别名$set)、$project(别名$unset),以及 $replaceRoot(别名$replaceWith)。

> db.processes.findOneAndUpdate({"status" : "READY"}, {"$set" : {"status" : "RUNNING"}},{"sort" : {"priority" : -1}})

返回修改后的值

> db.processes.findOneAndUpdate({"status" : "READY"},{"$set" : {"status" : "RUNNING"}},{"sort" : {"priority" : -1},"returnNewDocument": true})

findOneAndReplace:接受相同的参数,并根据 returnNewDocument 选项的值,返回替换之前或之后的文档。
findOneAndDelete:与上边类似,只是返回被删除的文档。

五、查询

1、find和findOne

find和findOne使用相同的参数,find返回多条文档,findOne返回一条文档。

查询文档中添加键–值对时,就意味着限定了查询条件。

> db.users.find({"username" : "joe", "age" : 27})

指定要返回的字段

> db.users.find({}, {"username" : 1, "email" : 1})

剔除某些字段

> db.users.find({}, {"fatal_weakness" : 0})

2、查询条件

2.1、查询条件

“$lt”、“$lte”、“$gt” 和 “$gte” 都属于比较运算符,分别对应 <、<=、> 和 >=。可以将它们组合使用以查找一个范围内的值。

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})

条件运算符 “$ne” 了,它表示“不相等”。

> db.users.find({"username" : {"$ne" : "joe"}})

2.2、OR查询

两种方式可以进行 OR 查询。“$in” 和"$or" 。

> db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}})
> db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" :true}]})

与 “$in” 相反的是 “$nin”

> db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}})

“$or” 可以包含其他条件。

> db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542,390]}}, {"winner" : true}]})

2.3、$not

取模运算符 “$mod” ,“$mod” 会将查询的值除以第一个给定值,如果余数等于第二个给定值,则匹配成功:

> db.users.find({"id_num" : {"$mod" : [5, 1]}})

“$not” 是一个元条件运算符:可以用于任何其他条件之上。

> db.users.find({"id_num" : {"$not" : {"$mod" : [5, 1]}}})

3、特定类型的查询

3.1、null

查询 “y” 键为 null 的文档,还会返回缺少这个键的所有文档

> db.c.find({"y" : null})

如果仅想匹配键值为 null 的文档,则需要检查该键的值是否为null,并且通过 “$exists” 条件确认该键已存在。

> db.c.find({"z" : {"$eq" : null, "$exists" : true}})

3.2、正则表达式

“$regex” 可以在查询中为字符串的模式匹配提供正则表达式功能。
用户名为 Joe 或 joe 的用户,那么可以使用正则表达式进行不区分大小写的匹配:

> db.users.find( {"name" : {"$regex" : /joe/i } })

如果除了匹配各种大小写组合形式的“joe”之外,还希望匹配如“joey”这样的键,那么可以改进一下刚刚的正则表达式:

> db.users.find({"name" : /joey?/i})

3.3、查询数组

01. “$all”
“$all” 查询来找到同时包含元素 “apple” 和"banana" 的文档

db.food.find({fruit : {KaTeX parse error: Expected 'EOF', got '}' at position 26: …ple", "banana"]}̲}) 在数组中查询特定位置的元…size"**
KaTeX parse error: Expected '}', got 'EOF' at end of input: …d({"fruit" : {"size” : 3}})
03. “$slice”
find 的第二个参数是可选的,可以指定需要返回的键。
返回前 10 条评论:

> db.blog.posts.findOne({}, {"comments" : {"$slice" :10}})

返回后 10 条评论,则可以使用 -10:

> db.blog.posts.findOne({}, {"comments" : {"$slice" :-10}})

“$slice” 也可以指定偏移量和返回的元素数量来获取数组中间的结果,例如返回第 24~33 个元素。

> db.blog.posts.findOne(criteria, {"comments" : {"$slice" :[23, 10]}})

使用 “$slice” 来获取最后一条评论,如下所示:

> db.blog.posts.findOne(criteria, {"comments" : {"$slice" :-1}})

04. 返回一个匹配的数组元素
可以使用$ 运算符来返回匹配的元素。

> db.blog.posts.find({"comments.name" : "bob"},{"comments.$" : 1})

05. 数组与范围查询的相互作用
如 “x” 必须同时满足大于 10 且小于 20

> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}})

可以使用min 和 max 将查询条件遍历的索引范围限制为 “ g t " 和 " gt" 和" gt""lt” 的值:

> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}}).min({"x" :10}).max({"x" : 20})

3.4、查询内嵌文档

查询内嵌文档的方法有两种:查询整个文档或针对其单个键–值对进行查询。

{
 "name" : {
 "first" : "Joe",
 "last" : "Schmoe"
 },
 "age" : 45
}

查询整个内嵌文档的工作方式与普通查询相同。

> db.people.find({"name" : {"first" : "Joe", "last" :"Schmoe"}})

针对内嵌文档的特定键进行查询。

> db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"})

4、$where查询

“$where” 子句,可以使用JavaScript 代码。

db.foo.find({"KaTeX parse error: Expected '}', got '&' at position 102: …rrent != other &̲& this[current]…where"比常规查询慢得多,并且BSON 转换为 JavaScript 对象,然后通过 “$where” 表达式运行,此外也无法使用索引。
3.6 增加了 $expr 运算符,它允许在查询语句中使用聚合表达式。因为它不需要执行 JavaScript,所以速度比 $where 快,建议尽可能使用此运算符作为替代。

5、游标

调用 find 时,shell 并不会立即查询数据库,而是等到真正开始请求结果时才发送查询,这样可以在执行之前给查询附加额外的选项。

> var cursor = db.foo.find().sort({"x" : 1}).limit(1).skip(10);
> var cursor = db.foo.find().limit(1).sort({"x" : 1}).skip(10);
> var cursor = db.foo.find().skip(10).limit(1).sort({"x" : 1});

要遍历结果,可以在游标上使用 next 方法。可以使用 hasNext 检查是否还有其他结果。

> while (cursor.hasNext()) {
 obj = cursor.next();
... 
}

六、索引

1、索引操作

创建 db.collection.createIndex(keys, options)
查看 db.collection.getIndexes()
删除某条 db.collection.dropIndex()
删除全部 db.collection.dropIndexes()

1.1、创建索引

db.users.createIndex({“firstname” : 1},{“name”:“index_firstname”, “unique” : true, “sparse”:true, “partialFilterExpression”:{“firstname”: {$exists: true } } } )

参数说明
unique:Boolean,建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name: string,索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
partialFilterExpression :Boolean,部分索引提供了稀疏索引功能的超集,使用一个文档来表示希望在其上创建索引的过滤器表达式。
MongoDB 4.2 引入了混合索引创建。它只在索引创建的开始和结束时持有排他锁,创建过程的其余部分会交错地让步于读写操作。

1.2、查询语句中加上explain,检查索引是否命中

db.users.find({“username”:“user101”}).explain(“executionStats”)
使用索引可以显著缩短查询时间,但是修改索引字段的写操作(插入、更新和删除)会花费更长的时间。因为在更改数据时,除了更新文档,MongoDB 还必须更新索引。

1.3、优化策略

(1)等值过滤的键应该在最前面;
(2)用于排序的键应该在多值字段之前;
(3)多值过滤的键应该在最后面;比如{age:15,score:{ l t : 70 , lt:70, lt:70,gt:60}}
(4)选择键的方向,使用与排序方向一样的索引。
(5)使用覆盖查询
如果查询只需要查找索引中包含的字段,那就没有必要去获取实际的文档了。
(6)隐式索引,复合索引具有“双重功能”,而且针对不同的查询可以充当不同的索引。
比如索引{name:1,age:1,score:1}
可以用在{name:usser001}条件查询,也可以用{name:user002,age:15}条件查询

七、特殊的索引和集合类型

1、地理空间索引

MongoDB 中对经纬度的存储有两种方式,分别是 Legacy Coordinate Pairs和 GeoJSON 。

1.1、Legacy Coordinate Pairs格式

数组形式:
{loc:[40.739037, 73.992964]}
嵌入文档形式
{loc:{lon:40.739037,lat:73.992964}}

1.2、GeoJSON格式

点格式
{“geometry1”: {
“type”: “Point”,
“coordinates”: [125.6, 10.1]
}}
线格式
{“geometry2”: {
“type”: “LineString”,
“coordinates”: [[125.6, 10.1],[125.6,10.2],[125.6,10.3]]
}}
多边形格式
{“geometry3”: {
“type”: “Polygon”,
“coordinates”: [[125.6, 10.1],[125.5,10.2],[125.7,10.3]]
}}
geometry名字可以随便取,但是内部字段固定。

1.3、地理空间查询

交集(“$geoIntersects”)、包含(“$geoWithin”)和接近( “$geoNear”)。
MongoDB 支持的查询类型和几何类型

查询类型 几何类型
$near(GeoJSON 坐标,2dsphere 索引) 球面
$near(遗留坐标,2d 索引) 平面
$geoNear(GeoJSON 坐标,2dsphere 索引) 球面
$geoNear(遗留坐标,2d 索引) 平面
$nearSphere(GeoJSON 坐标,2dsphere 索引) 球面
$nearSphere(遗留坐标,2d 索引)a 球面
$geoWithin : { $geometry: … } 球面
$geoWithin : { $box: … } 平面
$geoWithin : { $polygon: … } 平面
$geoWithin : { $center: … } 平面
$geoWithin : { $centerSphere: … } 球面
$geoIntersects 球面

创建球面 2dsphere 索引

> db.neighborhoods.createIndex({geometry:"2dsphere"})

创建平面2d索引

> db.hyrule.createIndex({"loc" : "2d"})

1.3.1、根据坐标查找所处街区

db.locations.findOne({geometry:{KaTeX parse error: Expected '}', got 'EOF' at end of input: …eoIntersects: {geometry:{type:“Point”,coordinates:[-75.93414657,41.82302903]}}}})

1.3.2、查找区域内所有人

db.users.find(
{location: {KaTeX parse error: Expected '}', got 'EOF' at end of input: geoWithin: {geometry: neighborhood.geometry3}}},
{username: 1, _id: 0}
);

1.3.3、返回指定距离内的人(无序)

> db.users.find({location: {$geoWithin: {$centerSphere: [[-73.93414657,40.82302903],5/3963.2]}}})

“$centerSphere” 的第二个参数会接受以弧度表示的半径。该查询通过除以长度大约为 3963.2 英里的地球赤道半径将距离转换为弧度。

db.restaurants.find({location: {$nearSphere: {$geometry: {type: "Point",coordinates:[-73.93414657,40.82302903]},$maxDistance: 5*1609.34}}});

使用 “$nearSphere” 并指定一个以米为单位的**“$maxDistance”**。这样做会返回距离用户 5 英里内的所有用户,并按由近到远的顺序进行排序。

2、全文搜索索引

全文索引使用 Apache Lucene 来提供搜索功能,与普通的文本索引不同
创建 “title” 字段和 “body” 字段索引:

> db.collection1.createIndex({"title": "text","body" : "text"})

也可以为每个字段指定权重:

> db.collection1.createIndex({"title": "text","body": "text"},{"weights" : {"title" : 3,"body" : 2}})

对所有字段设置全文索引

> db.collection1.createIndex({"$**" : "text"})

查询的时候使用text索引

db.collection1.find({$text: { $search: inputValue}})

计算文档得分,存储在textScore,并按分值排序

db.collection1.find({$text: { $search: inputValue}}, {score: {$meta: "textScore"}}).sort({ score:{$meta: "textScore"} })

关于全文索引的基本知识点
(1)text索引只能创建于类型为string或者string类型数组的字段
(2)双引号表示与,比如 { $text: { $search: “\“coffee shop\”” } } 表示同时包含coffee和shop
(3)没有双引号只有空格表示或, 比如 { $text: { $search: “coffee shop” } 表示包含coffee 或者 shop
(4)不包含用减号, 比如 { $text: { $search: “shop -coffee” } } 表示包含shop但是不包含coffee

默认为英语,可以设置为其它语言

> db.users.createIndex({"profil" : "text","intérêts" : "text"},{"default_language" : "french"})

当前支持的语言

Language Name ISO 639-1 (Two letter codes)
danish da
dutch nl
english en
finnish fi
french fr
german de
hungarian hu
italian it
norwegian nb
portuguese pt
romanian ro
russian ru
spanish es
swedish sv
turkish tr
对于暂不支持的语言,全文索引将用使用简单的停用词来词,比如中文,会使用空格或符号来分词

3、固定集合

固定集合指的是事先创建而且大小固定的集合,固定集合很像队列,如果空间不足,最早的文档就会被删除。
优点
(1).写入速度更快。
(2).固定集合会自动覆盖掉最老的文档。
应用场景
日志文件,聊天记录,通话信息记录,固定长度的推荐文章等,只保存一定大小的历史记录,过期的则会进行删除!

固定集合需要先创建才能使用
例如,创建固定集合coll_penngo,空间大小限制为100000个字节。

db.createCollection("coll_penngo",{capped:true,size:100000});

除了空间大小,还可以指定文档的数据量大小。
例如,创建固定集合coll_penngo,空间大小为100000个字节,文档数量大小为100条记录。

db.createCollection("coll_penngo",{capped:true,size:100000,max:100});

可以将普通集合装换为固定集合,使用的命令是 convertToCapped。
例如将testcol1集合转换为一个大小为1024字节的固定集合:
db.runCommand({“convertToCapped”:“testcollection”,“size”:100000})

固定集合信息的查看
(1)判断集合是否为固定集合:
db.coll_penngo.isCapped()。

(2)从集合信息中获取有关固定集合的属性:
db.coll_penngo.stats()

注意事项:
(1)固定集合的文档不能删除,但是可以删除整个集合。对固定集合中的文档可以进行更新或替换操作,如果大于限定的空间和数量,都会失败。
(2)普通集合可以使用 convertToCapped转换固定集合,但是固定集合不可以转换为普通集合。使用普通集合转换固定集合时,原有的索引会丢失,需要重新创建。
(3)创建固定集合,为固定集合指定文档数量限制时(指参数max),必须同时指定固定集合的空间大小(指参数size)。对集合估算size时,不要依据集合的storageSize ,而是依据集合的size。storageSize是wiredTiger存储引擎采用高压缩算法压缩后的。不管先达到哪一个限制,之后插入的新文档都会把最老的文档移除集合。
(4)固定集合不能分片。

可追加游标
在访问固定集合的结果集,可以使用可追加游标,当结果遍历完,游标不关闭,继续等待新数据。mongo shell 不允许可追加游标,PHP 中使用可追加游标的例子:

$cursor = $collection->find([], [
 'cursorType' => MongoDB\Operation\Find::TAILABLE_AWAIT,
 'maxAwaitTimeMS' => 100,
]);
while (true) {
 if ($iterator->valid()) {
 $document = $iterator->current();
 printf("penngo固定集合: %s\n", $document-
>createdAt);
 }
 $iterator->next();
}

这个游标不会自己关闭,直到游标超时功人为中止。

4、TTL索引

TTL索引介绍
TTL全称是(Time To Live),TTL索引可以设置数据的有效时间,自动删除过期的数据,可以在对字段创建索引时添加expireAfterSeconds参数将索引转换为TTL索引,该字段必需是date类型,在以下几种场景下即使索引设置了expireAfterSeconds属性也不会生效

  • 如果该字段不是date类型,则文档不会过期
  • 如果文档没包含索引的这个字段,则文档不会过期

TTL索引运行逻辑
MongoDB会开启一个后台线程来判断该TTL索引的值是否过期,不过并不能保证已过期的数据会立即被删除,因为后台线程每60秒触发一次删除任务,如果删除的数据量较大,存在删除不完,保留超过60秒以上的情况。
对于副本集而言,TTL索引的后台进程只会在primary节点开启,在从节点会始终处于空闲状态,从节点的数据删除是由主库删除后产生的oplog来做同步。
TTL索引除了有expireAfterSeconds属性外,和普通索引一样。

TTL索引的使用场景
(1)指定具体的过期时间属性
该场景是在创建索引时明确指定一个expireAfterSeconds时间作为文档的过期时间
// 对log_events集合的createdAt字段创建TTL索引且设置expireAfterSeconds过期时间为3600秒(1小时)
db.log_events.createIndex( { “createdAt”: 1 }, { expireAfterSeconds: 3600 } )
//文档插入数据,包含createdAt字段,则该文档会在1小时候后删除

(2)插入一个具体的过期时间
在创建索引时将expireAfterSeconds设置为0,在这种情况下由插入到字段的数据来控制文档何时过期,这种场景更加精细化,可灵活的控制文档的过期时间及控制在业务低峰期触发文档过期
// 对log_events集合的expireAt创建TTL索引,并设置expireAfterSeconds属性为0

db.log_events.createIndex( { “expireAt”: 1 }, { expireAfterSeconds: 0 } )
// 对文档插入数据,包含expireAt字段,该文档过期时间就是expireAt字段记录的时间
db.log_events.insert({“expireAt”: new Date(‘2022-09-01 00:00:00’),“logEvent”: 2,})

(3)TTL属性的修改(collMod)
对于TTL索引的expireAfterSeconds的属性,可以用collMod方式进行修改,修改索引定义,将一小时文档过期改为60秒
db.runCommand( { collMod: “log_events”,index: { keyPattern: { createdAt: 1 },expireAfterSeconds: 60}})

5、使用GridFS存储文件

mongoDB除了保存各种文档(JOSN结构)外还能够保存文件。GridFS规范提供了一种透明机制,可以将一个大文件分割成为多个较小的文档,这样的机制允许我们有效的保存大文件对象,特别对于那些巨大的文件,比如视频、高清图片等。

GridFS使用两个集合(fs.files与fs.chunks)来存储数据:
fs.files:包含元数据对象
文件的元数据放在这个集合里面,默认fs.files。这个里面的每个文档表示GridFS中的一个文件,与文件相关的自定义元数据也保存在其中,除了用户自定义的键,GridFS还有默认的一些键:
_id:文件唯一的id,在块中为“files_id”键的值存储
length:文件内容总的字节数
chunksize:每块的大小,以字节为单位。默认25K,可以调整
uploadDate:文件存入的时间
md5:文件内容的md5校验,由服务端生成
chunks:包含其他一些相关信息的二进制块

fs.chunks:块的集合。这个块集合的文档结构:
_id:标志唯一
n:表示块的编号,也就是这个块在原文件中的顺序号
data:包含组成文件块的二进制数据
files_id: 包含这个块元数据的文件文档的"_id"

mongofiles命令,可以用来在 GridFS 中上传文件、下载文件、查看文件列表、搜索文件,以及删除文件。
put:将文件系统中的一个文件添加到GridFS

mongofiles.exe put foo.txt  

list:会把所有添加到GridFS中的文件列出来

mongofiles.exe list  

get:put的反向操作

mongofiles.exe get foo.txt  

mongofiles 还支持另外两种操作:用于在 GridFS 中搜索文件的 search 操作和用于从GridFS 中删除文件的 delete 操作。

文章内容来自官网和网络整理
mongodb官网:https://www.mongodb.com/docs/manual/reference/

你可能感兴趣的:(数据库,数据库架构)