一、 安装
下载地址: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
port=27017
启动命令
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" : "joe@example.com", "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" : "joe@gmail.com"}})
还可以将 “$addToSet” 与 “$each” 结合使用,以添加多个不同的值,而这不能使用 “$ne” 和 “$push” 的组合来实现。
>db.users.updateOne({"_id" :ObjectId("4b2d75476cc613d5ee930164")},{"$addToSet" : {"emails" : {"$each" :["joe@php.net","joe@example.com","joe@python.org"]}}})
"$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)
updateMany与 updateOne接受相同的参数,区别在于被更改的文档数量。
> db.users.updateMany({"birthday" : "10/13/1978"}, {"$set" : {"gift" : "Happy Birthday!"}})
3.2 版本中 shell 引入了 3 个新的集合方法来提供findAndModify 的功能:findOneAndDelete、findOneAndReplace 和findOneAndUpdate。与 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/
|