mongodb
非关系型数据库
memcached
redis kv数据库(key/value)
mongodb
mongodb 文档数据库,存储的是文档(Bson->json的二进制化).
特点: 内部执行引擎为JS解释器, 把文档存储成bson结构,在查询时,转换为JS对象,并可以通过熟悉的js语法来操作.
mongo和传统型数据库相比,最大的不同:
传统型数据库: 结构化数据, 定好了表结构后,每一行的内容,必是符合表结构的,就是说–列的个数,类型都一样.
mongo文档型数据库: 表下的每篇文档,都可以有自己独特的结构(json对象都可以有自己独特的属性和值)
例如
如果有电影, 影评, 影评的回复, 回复的打分,在传统型数据库中, 至少要4张表, 关联度非常复杂。在文档数据库中,通过1篇文档,即可完成。体现出文档型数据库的反范式化.
{
fiim:’天龙八部’
comment:[{content:’王家卫的电影风格’, reply:[‘支持’,’好’]}]
}
mongodb的安装
1: 下载mongodb: https://www.mongodb.org 下载最新的stable版
2: 解压文件
3: 不用编译,本身就是编译后的二进制可执行文件.
4: 启动mongod服务
./bin/mongod --dbpath /path/to/database --logpath /path/to/log --fork --port 27017
参数解释:
--dbpath 数据存储目录
--logpath 日志存储目录
--port 运行端口(默认27017)
--fork 后台进程运行
5: mongodb非常的占磁盘空间, 刚启动后要占3-4G左右。如果你用虚拟机练习,可能空间不够,导致无法启动。可以用 --smallfiles 选项来启动,
将会占用较小空间 400M左右.
mongo入门命令
1. show dbs 查看当前的数据库
2. use databaseName 选库
3. show tables/collections 查看当前库下的collection
创建库
Mongodb的库是隐式创建,你可以use 一个不存在的库
然后在该库下创建collection,即可创建库
1. db.createCollection(‘collectionName’) 创建collection
2. collection允许隐式创建 Db.collectionName.insert(document);
3. db.collectionName.drop() ,删除collection
4. db.dropDatabase(); 删除database
基本操作 增删改查
增: insert
介绍: mongodb存储的是文档,. 文档是json格式的对象.
语法:
db.collectionName.insert(document);
插入文档你也可以使用 db.col.save(document)
命令。
- 如果不指定 _id 字段 save() 方法类似于 insert() 方法。
- 如果指定 _id 字段,则会更新该 _id 的数据。
插入 insert
-
增加单篇文档
Db.collectionName.insert({title:’nice day’});
-
增加单个文档,并指定_id
Db.collectionName.insert({_id:8,age:78,name:’lisi’});
-
增加多个文档
db.collectionName.insert([ {time:'friday',study:'mongodb'}, {_id:9,gender:'male',name:'QQ'} ]);
删:remove
语法:
MongoDB remove()函数是用来移除集合中的数据。
MongoDB数据更新可以使用update()函数。
在执行remove()函数前先执行find()命令来判断执行的条件是否正确,这是一个比较好的习惯。
MongoDB 是 2.6 版本以后的,语法格式如下:
db.collection.remove(<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
- query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档。
- writeConcern :(可选)抛出异常的级别。
注意
- 查询表达式依然是个json对象
- 查询表达式匹配的行,将被删掉.
- 如果不写查询表达式,collections中的所有文档将被删掉.
例1:
db.stu.remove({sn:’001’}); 删除stu表中 sn属性值为’001’的文档
例2:
db.stu.remove({gender:’m’,true}); 删除stu表中gender属性为m的文档,只删除1行.
更新update
update() 方法
语法:
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
参数说明:
- query : update的查询条件,类似sql update查询内where后面的。
- update : update的对象和一些更新的操作符(如$,$inc…)等,也可以理解为sql update查询内set后面的
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- **writeConcern ?*可选,抛出异常的级别。
例:
db.news.update({name:'QQ'},{name:'MSN'});
是指选中news表中,name值为QQ的文档,并把其文档值改为{name:’MSN’},
结果: 文档中的其他列也不见了,改后只有_id和name列了.
即–新文档直接替换了旧文档,而不是修改
如果是想修改文档的某列,可以用 $set 关键字
db.collectionName.update(query,{$set:{name:’QQ’}})
修改时的赋值表达式
$set 修改某列的值
$unset 删除某个列
$rename 重命名某个列
$inc 增长某个列
$setOnInsert 当upsert为true时,并且发生了insert操作时,可以补充的字段.
例:
db.stu.update({name:'wuyong'},{$set:{name:'junshiwuyong'}},{upsert:true});
如果有name=’wuyong’的文档,将被修改, 如果没有,将添加此新文档
例:
db.news.update({_id:99},{x:123,y:234},{upsert:true});
没有_id=99的文档被修改,因此直接插入该文档
例:
db.news.update({age:21},{$set:{age:22}},{multi:true});
则把news中所有age=21的文档,都修改
save() 方法
save() 方法通过传入的文档来替换已有文档。语法格式如下:
db.collection.save(
<document>,
{
writeConcern: <document>
}
)
参数说明:
document : 文档数据。
writeConcern :可选,抛出异常的级别。
查询
查: find, findOne
语法:
db.collection.find(查询表达式,查询的列);
Db.collections.find(表达式,{列1:1,列2:1});
例1:
db.stu.find();
查询所有文档 所有内容
例2:
db.stu.find({},{gendre:1});
查询所有文档,的gender属性 (_id属性默认总是查出来)
例3:
db.stu.find({},{gender:1, _id:0});
查询所有文档的gender属性,且不查询_id属性
例4:
db.stu.find({gender:’male’},{name:1,_id:0});
查询所有gender属性值为male的文档中的name属性
查询表达式:
-
最简单的查询表达式
{filed:value}
,是指查询field列的值为value的文档 -
$ne — != 查询表达式
{field:{$ne:value}}
查filed列的值 不等于 value 的文档 -
$nin --> not in
-
$all
语法:{field:{$all:[v1,v2..]}}
是指取出 field列是一个数组,且至少包含 v1,v2值 -
$exists
语法:{field:{$exists:1}}
查询出含有field字段的文档 -
$nor,
语法:{$nor,[条件1,条件2]}
是指 所有条件都不满足的文档为真返回 -
用正则表达式查询 以”诺基亚”开头的商品
例:db.goods.find({goods_name:/诺基亚.*/},{goods_name:1});
-
用$where表达式来查询
例:db.goods.find({$where:'this.cat_id != 3 && this.cat_id != 11'});
注意:
用$where查询时, mongodb是把bson结构的二进制数据转换为json结构的对象, 然后比较对象的属性是否满足表达式.
速度较慢
Update时可用的操作符
例:
db.user.insert({name:'lisi',age:12,sex:'male',height:123,area:'haidian'});
db.user.update({name:'lisi'}, {\$set:{area:'chaoyang'},
\$unset:{height:1},
\$inc:{age:1},
\$rename:{sex:'gender'}
});
db.user.find();
{
"_id" : ObjectId("51fc01c4f5de93e1f2856e33"),
"age" : 13, "area" : "chaoyang",
"gender" : "male", "name" : "lisi"
}
$setOnInsert ->相当于mysql中的列的默认值
游标操作 cursor
游标是什么?
通俗的说,游标不是查询结果,而是查询的返回资源,或者接口.
通过这个接口,你可以逐条读取.
就像php中的fopen打开文件,得到一个资源一样, 通过资源,可以一行一行的读文件.
声明游标:
var cursor = db.collectioName.find(query,projection);
Cursor.hasNext() ,判断游标是否已经取到尽头
Cursor. Next() , 取出游标的下1个单元
用while来循环游标
var mycursor = db.bar.find({_id:{$lte:5}})
while(mycursor.hasNext()) {
… printjson(mycursor.next());
… }
例:
// 声明游标
var cursor = db.goods.find();
// 循环游标
for(var doc=true;cursor.hasNext();) { printjson(cursor.next());}
也可以简写:
for(var cursor=db.goods.find(), doc=true;cursor.hasNext();) {
printjson(cursor.next());
}
游标还有一个迭代函数,允许我们自定义回调函数来逐个处理每个单元.
cursor.forEach(回调函数);
例:
var gettitle = function(obj) {print(obj.goods_name)}
var cursor = db.goods.find();
cursor.forEach(gettitle);
游标在分页中的应用
比如查到10000行,跳过100页,取10行.
一般地,我们假设每页N行, 当前是page页
就需要跳过前 (page-1)*N 行, 再取N行, 在mysql中, limit offset,N来实现
在mongo中,用skip(), limit()函数来实现的
如 var mycursor = db.bar.find().skip(9995); 则是查询结果中,跳过前9995行
查询第901页,每页10条
则是 var mytcursor = db.bar.find().skip(9000).limit(10);
通过cursor一次性得到所有数据, 并返回数组.
例:
var cursor = db.goods.find();
printjson(cursor.toArray()); //看到所有行
printjson(cursor.toArray()[2]); //看到第2行
注意: 不要随意使用toArray()
原因: 会把所有的行立即以对象形式组织在内存里.
可以在取出少数几行时,用此功能.
索引创建
- 索引提高查询速度,降低写入速度,权衡常用的查询字段,不必在太多列上建索引
- 在mongodb中,索引可以按字段升序/降序来创建,便于排序
- 默认是用btree来组织索引文件,2.4版本以后,也允许建立hash索引.
查看查询计划
db.find(query).explain();
"cursor" : "BasicCursor", ----说明没有索引发挥作用
"nscannedObjects" : 1000 ---理论上要扫描多少行
cursor" : "BtreeCursor sn_1", 用到的btree索引
常用命令:
查看当前索引状态: db.collection.getIndexes();
创建普通的单列索引: db.collection.ensureIndex({field:1/-1}); 1是升续 2是降续
删除单个索引: db.collection.dropIndex({filed:1/-1});
删除所有索引: db.collection.dropIndexes();
创建多列索引: db.collection.ensureIndex({field1:1/-1, field2:1/-1});
创建子文档索引: db.collection.ensureIndex({filed.subfield:1/-1});
创建唯一索引: db.collection.ensureIndex({filed.subfield:1/-1}, {unique:true});
创建稀疏索引:
稀疏索引的特点
-
如果针对field做索引,针对不含field列的文档,将不建立索引.
与之相对,普通索引,会把该文档的field列的值认为NULL,并建索引.
适宜于: 小部分文档含有某列时db.collection.ensureIndex({field:1/-1},{sparse:true}); db.tea.find(); { "_id" : ObjectId("5275f99b87437c610023597b"), "email" : "a@163.com" } { "_id" : ObjectId("5275f99e87437c610023597c"), "email" : "b@163.com" } { "_id" : ObjectId("5275f9e887437c610023597e"), "email" : "c@163.com" } { "_id" : ObjectId("5275fa3887437c6100235980") }
如上内容,最后一行没有email列,
如果分别加普通索引,和稀疏索引,
对于最后一行的email分别当成null 和 忽略最后一行来处理.
根据{email:null}来查询,前者能查到,而稀疏索引查不到最后一行.
创建哈希索引(2.4新增的)
哈希索引速度比普通索引快,但是,无能对范围查询进行优化.
适宜于—随机性强的散列
db.collection.ensureIndex({file:’hashed’});
重建索引
一个表经过很多次修改后,导致表的文件产生空洞,索引文件也如此.
可以通过索引的重建,减少索引文件碎片,并提高索引的效率.
类似mysql中的optimize table
db.collection.reIndex()
Mongodb导出与导入
-
导入/导出可以操作的是本地的mongodb服务器,也可以是远程的.
所以,都有如下通用选项:
-h host 主机
–port port 端口
-u username 用户名
-p passwd 密码 -
mongoexport 导出json格式的文件
问: 导出哪个库,哪张表,哪几列,哪几行?
-d 库名
-c 表名
-f field1,field2…列名
-q 查询条件
-o 导出的文件名
– csv 导出csv格式(便于和传统数据库交换数据)
例:
[root@localhost mongodb]# ./bin/mongoexport -d test -c news -o test.json
connected to: 127.0.0.1
exported 3 records
[root@localhost mongodb]# ls
bin dump GNU-AGPL-3.0 README test.json THIRD-PARTY-NOTICES
[root@localhost mongodb]# more test.json
{ “_id” : { “$oid” : “51fc59c9fecc28d8316cfc03” }, “title” : “aaaa” }
{ “_id” : { “$oid” : “51fcaa3c5eed52c903a91837” }, “title” : “today is sataday” }
{ “_id” : { “$oid” : “51fcaa445eed52c903a91838” }, “title” : “ok now” }
例2: 只导出goods_id,goods_name列
./bin/mongoexport -d test -c goods -f goods_id,goods_name -o goods.json
例3: 只导出价格低于1000元的行
./bin/mongoexport -d test -c goods -f goods_id,goods_name,shop_price -q ‘{shop_price:{$lt:200}}’ -o goods.json
注: _id列总是导出
Mongoimport 导入
- -d 待导入的数据库
- -c 待导入的表(不存在会自己创建)
- –type csv/json(默认)
- –file 备份文件路径
例1: 导入json
./bin/mongoimport -d test -c goods --file ./goodsall.json
例2: 导入csv
./bin/mongoimport -d test -c goods --type csv -f goods_id,goods_name --file ./goodsall.csv
./bin/mongoimport -d test -c goods --type csv --headline -f goods_id,goods_name --file ./goodsall.csv
mongodump 导出二进制bson结构的数据及其索引信息
- -d 库名
- -c 表名
- -f field1,field2…列名
例:
mongodum -d test [-c 表名] 默认是导出到mongo下的dump目录
**规律: **
- 导出的文件放在以database命名的目录下
- 每个表导出2个文件,分别是bson结构的数据文件, json的索引信息
- 如果不声明表名, 导出所有的表
mongorestore 导入二进制文件
例:
./bin/mongorestore -d test --directoryperdb dump/test/ (mongodump时的备份目录)
二进制备份,不仅可以备份数据,还可以备份索引,
备份数据比较小.
mongodb的用户管理
注意:
A) 在mongodb中,有一个admin数据库, 牵涉到服务器配置层面的操作,需要先切换到admin数据.
即 use admin , -->相当于进入超级用户管理模式.
B) mongo的用户是以数据库为单位来建立的, 每个数据库有自己的管理员.
C) 我们在设置用户时,需要先在admin数据库下建立管理员—这个管理员登陆后,相当于超级管理员.
3.0版本以前
在mongodb3.0版本以前中,有一个admin数据库, 牵涉到服务器配置层面的操作,需要先切换到admin数据库.即 use admin , 相当于进入超级用户管理模式,mongo的用户是以数据库为单位来建立的, 每个数据库有自己的管理员.我们在设置用户时,需要先在admin数据库下建立管理员—这个管理员登陆后,相当于超级管理员.
命令:db.addUser();
简单参数: db.addUser(用户名,密码,是否只读)
- 注意: 添加用户后,我们再次退出并登陆,发现依然可以直接读数据库?
原因: mongodb服务器启动时, 默认不是需要认证的.
要让用户生效, 需要启动服务器时,就指定–auth选项.这样, 操作时,就需要认证了.
添加用户
use admin
db.addUser(‘admin’,‘admin’,false); # 3.0版本更改为createUser();
删除用户
use test
db.removeUser(用户名); # 3.0版本更改为dropUser();
3.0版本以后
创建管理员
在3.0版本以后,mongodb默认是没有admin这个数据库的,并且创建管理员不再用addUser,而用createUser;
语法说明
{ user: "<name>",
pwd: "<cleartext password>",
customData: { <any information> }, # 任意的数据,一般是用于描述用户管理员的信息
roles: [
{ role: "<role>", db: "<database>" } | "<role>", # 如果是role就是直接指定了角色,并作用于当前的数据库
...
] # roles是必传项,但是可以指定空数组,为空就是不指定任何权限
}
Built-In Roles(内置角色):
数据库用户角色:read、readWrite
数据库管理角色:dbAdmin、dbOwner、userAdmin
集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
备份恢复角色:backup、restore
所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
超级用户角色:root
这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase
)
内部角色:__system
PS:关于每个角色所拥有的操作权限可以点击上面的内置角色链接查看详情。
官方Example
use products # mongoDB的权限设置是以库为单位的,必选要先选择库
db.createUser(
{ "user" : "accountAdmin01",
"pwd": "cleartext password",
"customData" : { employeeId: 12345 },
"roles" : [ { role: "clusterAdmin", db: "admin" },
{ role: "readAnyDatabase", db: "admin" },
"readWrite"
]
},{ w: "majority" , wtimeout: 5000 } )
# readWrite 适用于products库,clusterAdmin与readAnyDatabase角色适用于admin库
writeConcern文档(官方说明)
w选项:允许的值分别是 1、0、大于1的值、"majority"、;
j选项:确保mongod实例写数据到磁盘上的journal(日志),这可以确保mongd以外关闭不会丢失数据。设置true启用。
wtimeout:指定一个时间限制,以毫秒为单位。wtimeout只适用于w值大于1。
use shop;
db.createUser({
user:'admin',
pwd:'zhouzhou123',
roles:['dbOwner']
});
只要新加了一个用户,admin数据库就会重新存在;
mongo --host xxx -u admin -p zhouzhou123 --authenticationDatabase shop # 用新创建的用户登录
查看当前用户在shop数据库的权限
use shop;
db.runCommand({
usersInfo:"shopzhouzhou",
showPrivileges:true
});
查看用户信息
db.runCommand({usersInfo:"userName"})
创建一个不受访问限制的超级用户
use admin
db.createUser({
user:"superuser",
pwd:"pwd",
roles:["root"]
});
认证用户
use test
db.auth(用户名,密码); #注意是以库为单位,必须先选择库;
删除用户
use test
db.dropUser('用户名');
修改用户密码
use test
db.changeUserPassword(用户名, 新密码);
修改密码和用户信息
db.runCommand(
{
updateUser:"username",
pwd:"xxx",
customData:{title:"xxx"}
}
)
Replication set 设置全过程
-
创建目录
mkdir -p /data/r0 /data/r1 /data/r2
-
启动3个实例,且声明实例属于某复制集
./bin/mongod --port 27017 --dbpath /data/r0 --smallfiles --replSet rsa --fork --logpath /var/log/mongo17.log ./bin/mongod --port 27018 --dbpath /data/r1 --smallfiles --replSet rsa --fork --logpath /var/log/mongo18.log ./bin/mongod --port 27019 --dbpath /data/r2 --smallfiles --replSet rsa --fork --logpath /var/log/mongo19.log
2:配置
rsconf = {
_id:'rsa',
members:
[{_id:0, host:'192.168.1.201:27017'}]
}
-
根据配置做初始化
rs.initiate(rsconf);
-
添加节点
rs.add('192.168.1.201:27018'); rs.add('192.168.1.201:27019');
-
查看状态
rs.status();
-
删除节点
rs.remove('192.168.1.201:27019');
-
主节点插入数据
use test db.user.insert({uid:1,name:'lily'});
-
连接secondary查询同步情况
./bin/mongo --port 27019 use test show tables rsa:SECONDARY> show tables; Sat Aug 17 16:03:55.786 JavaScript execution failed: error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
8.1 出现上述错误,是因为slave默认不许读写
rs.slaveOk(); show tables
看到与primary 一致的数据
MongoDB 聚合
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。
aggregate() 方法
MongoDB中聚合的方法使用aggregate()。
语法
aggregate() 方法的基本语法格式如下所示:
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
实例
集合中的数据如下:
{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'w3cschool.cc',
url: 'http://www.w3cschool.cc',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: ObjectId(7df78ad8902d)
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'w3cschool.cc',
url: 'http://www.w3cschool.cc',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: ObjectId(7df78ad8902e)
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},
现在我们通过以上集合计算每个作者所写的文章数,使用aggregate()计算结果如下:
db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
"result" : [
{
"_id" : "w3cschool.cc",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
以上实例类似sql语句: select by_user, count(*) from mycol group by by_user
在上面的例子中,我们通过字段by_user字段对数据进行分组,并计算by_user字段相同值的总和。
下表展示了一些聚合的表达式:
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$sum : “$likes”}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$avg : “$likes”}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$min : “$likes”}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$max : “$likes”}}}]) |
$push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{$group : {_id : “$by_user”, url : {$push: “$url”}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不创建副本。 | db.mycol.aggregate([{$group : {_id : “$by_user”, url : {$addToSet : “$url”}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : “$by_user”, first_url : {$first : “$url”}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : “$by_user”, last_url : {$last : “$url”}}}]) |
管道的概念
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。
表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。
这里我们介绍一下聚合框架中常用的几个操作:
- $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
- $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
- $limit:用来限制MongoDB聚合管道返回的文档数。
- $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
- $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
- $group:将集合中的文档分组,可用于统计结果。
- $sort:将输入文档排序后输出。
- $geoNear:输出接近某一地理位置的有序文档。
管道操作符实例
1、$project实例
db.article.aggregate({$project : { title : 1 ,author : 1 }});
这样的话结果中就只还有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样:
db.article.aggregate({$project : {_id : 0 , title : 1 , author : 1}});
2.$match实例
db.articles.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
]);
$match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。
3.$skip实例
db.article.aggregate({ $skip : 5 });
经过$skip管道操作符处理后,前五个文档被"过滤"掉。