玩转计算
MongoDB属于NoSql中的基于分布式文件存储的文档型数据库,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,但是写起来并不简单。若能集算器SPL语言结合,处理起来就相对容易多了。
现在我们针对MongoDB在计算方面的问题进行讨论分析,通过集算器SPL语言加以改进,方便用户使用MongoDB。现从如下情况加以说明:
1。单表内嵌数组结构的统计。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。1
2。单表内嵌文档求和。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。3
3。分段分组结构。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。5
4。同构表合并。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。6
5。关联嵌套结构情况1。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。8
6。关联嵌套结构情况2。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。10
7。关联嵌套结构情况3。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。11
8。多字段分组统计。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。14
9。两表关联查询。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。16
10。多表关联查询。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。17
11。指定数组查找。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。19
12。关联表中的数组查找。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。20
1。单表内嵌数组结构的统计
对嵌套数组结构中的数据统计处理。查询考试科目的平均分及每个学生的总成绩情况。
测试数据:
脚本:
db。student。aggregate(〔
{unwind:scroe},
{group:{
id:{lesson:scroe。lesson},
qty:{avg:scroe。mark}
}
}
〕)db。student。aggregate(〔
{unwind:scroe},
{group:{
id:{name:name},
qty:{sum:scroe。mark}
}
}
〕)
由于各科分数scroe是按课目、成绩记录的数组结构,统计前需要将它拆解,将每科成绩与学生对应,然后再实现分组计算。这需要熟悉unwind与group组合的应用。
SPL脚本:
按课目统计的总分数
脚本说明:
A1:连接mongo数据库。
A2:获取student表中的数据。
A3:将scroe数据合并成序表,再按课程分组,计算平均分。
A4:统计每个学生的成绩后返回列名为NAME、TOTAL的序表。new函数表示生成新序表。
A5:关闭数据库连接。
这个比较常用嵌套结构统计的例子许多人遭遇过、需要先拆解,主要是熟悉mongodb对嵌套数据结构的处理。
2。单表内嵌文档求和
对内嵌文档中的数据求和处理,下面要统计每条记录的income,output的数量和。
测试数据:
Mongodb脚本:
varfields〔income,output〕;
db。computer。aggregate(〔
{
project:{
values:{
filter:{
input:{
objectToArray:ROOT
},
cond:{
in:〔
this。k,
fields
〕
}
}
}
}
},
{
unwind:values
},
{
project:{
key:values。k,
values:{
sum:{
let:{
vars:{
item:{
objectToArray:values。v
}
},
in:item。v
}
}
}
}
},
{sort:{id:1}},
{group:{
id:id,
income:{first:values},
output:{last:values}
}},
〕);
filter将income,output部分信息存放到数组中,用unwind拆解成记录,再累计各项值求和,按id分组合并数据。
SPL脚本:
脚本说明:
A1:连接数据库
A2:获取computer表中的数据
A3:将income、output字段中的数据分别转换成序列求和,再与ID组合生成新序表
A4:关闭数据库连接。
获取子记录的字段值,然后求和,相对于mongo脚本简化了不少。这个内嵌文档与内嵌数组在组织结构上有点类似,不小心容易混淆,注意与上例中的scroe数组结构比较,写出的脚本有所不同。
3。分段分组结构
统计各段内的记录数量。下面按销售量分段,统计各段内的数据量,数据如下:
分段方法:03000;30005000;50007500;750010000;10000以上。
期望结果:
Mongo脚本
varacount0;
varbcount0;
varccount0;
vardcount0;
varecount0;
db。sales。find({
})。forEach(
function(myDoc){
if(myDoc。SALESamp;lt;3000){
acount1;
}
elseif(myDoc。SALESamp;lt;5000){
bcount1;
}
elseif(myDoc。SALESamp;lt;7500){
ccount1;
}
elseif(myDoc。SALESamp;lt;10000){
dcount1;
}
else{
ecount1;
}
}
);
print(acountacount)
print(bcountbcount)
print(ccountccount)
print(dcountdcount)
print(ecountecount)
这个需求按条件分段分组,mongodb没有提供对应的api,实现起来有点繁琐,上面的程序是其中实现的一个例子参考,当然也可以写成其它实现形式。下面看看集算器脚本的实现。
SPL脚本:
脚本说明:
A1:定义SALES分组区间。
A2:连接mongodb数据库。
A3:获取sales表中的数据。
A4:根据SALES区间分组统计员工数。其中函数pseg()表示返回成员在序列中的区段序号,int()表示转换成整数。
A5:关闭数据库连接。
pseg的使用让SPL脚本精简了不少。
4。同构表合并
具有相同结构的多表数据合并。下面将两个员工表数据合并。
Emp1:
Mongo脚本:
db。emp1。aggregate(〔
{limit:1},
{facet:{
collection1:〔
{limit:1},
{lookup:{
from:emp1,
pipeline:〔{match:{}}〕,
as:collection1
}}
〕,
collection2:〔
{limit:1},
{lookup:{
from:emp2,
pipeline:〔{match:{}}〕,
as:collection2
}}
〕
}},
{project:{
data:{
concatArrays:〔
{arrayElemAt:〔collection1。collection1,0〕},
{arrayElemAt:〔collection2。collection2,0〕},
〕
}
}},
{unwind:data},
{replaceRoot:{newRoot:data}}
〕)
通过facet将两表数据先存入各自的数组中,然后concatArrays将数组合并,unwind拆解子记录后,并将它呈现在最外层。SPL脚本实现则没有那么多花样。
SPL脚本:
脚本说明:
A1:连接mongodb数据库。
A2:获取emp1表中的数据。
A3:获取emp2表中的数据。
A4:合并两表数据。
A5:关闭数据库连接。
熟悉sql语句的mongo初学者面对数据合并的mongo脚本,估计首次遇到时有点懵,SPL脚本就显得自然易懂了。
5。关联嵌套结构情况1
两个关联表,表A与表B中的内嵌文档信息关联,且返回的信息在内嵌文档中。表childsgroup字段childs是嵌套数组结构,需要合并的信息name在其下。
history:
表History中的childid与表childsgroup中的childs。id关联,希望得到下面结果:
{
id:ObjectId(5bab2ae8ab2f1bdb4f434bc3),
id:001,
history:todayworked,
childid:ch001,
childInfo:
{
name:a
}
}
Mongo脚本
db。history。aggregate(〔
{lookup:{
from:childsgroup,
let:{childid:childid},
pipeline:〔
{match:{expr:{in:〔childid,childs。id〕}}},
{unwind:childs},
{match:{expr:{eq:〔childs。id,childid〕}}},
{replaceRoot:{newRoot:childs。info}}
〕,
as:childInfo
}},
{unwind:childInfo}
〕)
这个脚本用了几个函数lookup、pipeline、match、unwind、replaceRoot处理,一般mongodb用户不容易写出这样复杂脚本;那我们再看看spl脚本的实现:
SPL脚本:
脚本说明:
A1:连接mongodb数据库。
A2:获取history表中的数据。
A3:获取childsgroup表中的数据。
A4:将childsgroup中的childs数据提取出来合并成序表。
A5:表history中的childid与表childs中的id关联查询,追加name字段,返回序表。
A6:关闭数据库连接。
相对mongodb脚本写法,SPL脚本的难度降低了不少,省去了熟悉有关mongo函数的用法,如何去组合处理数据等,节约了不少时间。
6。关联嵌套结构情况2
两个关联表,表A与表B中的内嵌文档信息关联,将信息合并到内嵌文档中。表txtPost字段comment是嵌套数组结构,需要把commentcontent合并到其下。
Mongo脚本
db。getCollection(txtPost)。aggregate(〔
{unwind:comment},
{lookup:{
from:txtComment,
localField:comment。commentno,
foreignField:commentno,
as:comment。commentcontent
}},
{unwind:comment。commentcontent},
{addFields:{comment。commentcontent:comment。commentcontent。commentcontent}},
{group:{
id:id,
postno:{first:postno},
comment:{push:comment}
}},
〕)。pretty()表txtPost按comment拆解成记录,然后与表txtComment关联查询,将其结果放到数组中,再将数组拆解成记录,将commentcontent值移到comment下,最后分组合并。
SPL脚本:
脚本说明:
A1:连接mongodb数据库。
A2:获取txtPost表中的数据。
A3:获取txtComment表中的数据。
A4:将序表A2下的comment与postno组合成序表,其中postno改名为pno。
A5:序表A4通过commentno与序表A3关联,追加字段commentcontent,将其改名为Content。
A6:按pno分组返回序表,表示当前记录。
A7:关闭数据库连接。
7。关联嵌套结构情况3
两个关联表,表A与表B中的内嵌文档信息关联,且返回的信息在记录上。表collection2字段product是嵌套数组结构,返回的信息是isCompleted等字段。
测试数据:
collection1:
{
id:5bc2e44a106342152cd83e97,
description:
{
status:Good,
machine:X
},
order:A,
lot:1
};
collection2:
{
id:5bc2e44a106342152cd83e80,
isCompleted:false,
serialNo:1,
batchNo:2,
product:〔notethesubdocumentshere
{order:A,lot:1},
{order:A,lot:2}
〕
}
期待结果
{
id:5bc2e44a106342152cd83e97,
description:
{
status:Good,
machine:X,
},
order:A,
lot:1,
isCompleted:false,
serialNo:1,
batchNo:2
}
Mongo脚本
db。collection1。aggregate(〔{
lookup:{
from:collection2,
let:{order:order,lot:lot},
pipeline:〔{
match:{
expr:{in:〔{order:order,lot:lot},product〕}
}
}〕,
as:isCompleted
}
},{
addFields:{
isCompleted:{arrayElemAt:〔isCompleted,0〕}
}
},{
addFields:{addtherequiredfieldstothetoplevelstructure
isCompleted:isCompleted。isCompleted,
serialNo:isCompleted。serialNo,
batchNo:isCompleted。batchNo
}
}〕)
lookup两表关联查询,首个addFields获取isCompleted数组的第一个记录,后一个addFields转换成所需要的几个字段信息
SPL脚本:
脚本说明:
A1:连接mongodb数据库。
A2:获取collection1表中的数据。
A3:获取collection2表中的数据。
A4:根据条件order,lot从序表A2中查询记录,然后追加序表A3中的字段serialNo,batchNo,返回合并后的序表。
A5:关闭数据库连接。
实现从数据记录中的内嵌结构中筛选,将符合条件的数据合并成新序表。
8。多字段分组统计
统计分类项下的总数及各子项数。下面统计按addr分类book数及其下不同的book数。
Mongo脚本
db。books。aggregate(〔
{group:{
id:{
addr:addr,
book:book
},
bookCount:{sum:1}
}},
{group:{
id:id。addr,
books:{
push:{
book:id。book,
count:bookCount
},
},
count:{sum:bookCount}
}},
{sort:{count:1}},
{project:{
books:{slice:〔books,2〕},
count:1
}}
〕)。pretty()
先按addr,book分组统计book数,再按addr分组统计book数,调整显示顺序
SPL脚本:
脚本说明:
A1:连接mongodb数据库。
A2:获取books表中的数据。
A3:按addr,book分组统计book数,
A4:再按addr分组统计book数。
A5:将A4中的Total按addr关联后合并到序表中。
A6:关闭数据库连接。
9。两表关联查询
从关联表中选择所需要的字段组合成新表。
Collection1:
Mongo脚本
db。c1。aggregate(〔
{lookup:{
from:c2,
localField:user1,
foreignField:user1,
as:collection2doc
}},
{unwind:collection2doc},
{redact:{
cond:〔
{eq:〔user2,collection2doc。user2〕},
KEEP,
PRUNE
〕
}},
{project:{
user1:1,
user2:1,
income:income,
output:collection2doc。output
}}
〕)。pretty()
lookup两表进行关联查询,redact对记录根据条件进行遍历处理,project选择要显示的字段。
SPL脚本:
脚本说明:
A1:连接mongodb数据库。
A2:获取c1表中的数据。
A3:获取c2表中的数据。
A4:两表按字段user1,user2关联,追加序表A3中的output字段,返回序表。
A5:关闭数据库连接。
通过join把两个关联表不同的字段合并成新表。
10。多表关联查询
多于两个表的关联查询,结合成一张大表。
合并后的结果:
{
id:ObjectId(5901a4c63541b7d5d3293766),
firstName:shubham,
lastName:verma,
address:{
address:Gurgaon
},
social:{
fbURLs:http:www。facebook。com,
twitterURLs:http:www。twitter。com
}
}
Mongo脚本
db。doc1。aggregate(〔
{match:{id:ObjectId(5901a4c63541b7d5d3293766)}},
{
lookup:
{
from:doc2,
localField:id,
foreignField:userId,
as:address
}
},
{
unwind:address
},
{
project:{
address。id:0,
address。userId:0,
address。mob:0
}
},
{
lookup:
{
from:doc3,
localField:id,
foreignField:userId,
as:social
}
},
{
unwind:social
},
{
project:{
social。id:0,
social。userId:0
}
}
〕)。pretty();
由于Mongodb数据结构原因,写法也多样化,展示也各不相同。
SPL脚本:
此脚本与上面例子类似,只是多了一个关联表,每次join就新增加字段,最后叠加构成一张大表。。
SPL脚本的简洁性、统一性就非常明显。
11。指定数组查找
从指定的数组中查找符合条件的记录。所给的数组为:〔Chemical,Biology,Math〕。
测试数据:
Mongodb脚本
varfield〔Chemical,Biology,Math〕
db。student。aggregate(〔
{project:{
name:1,
lessons:{
filter:{
input:lesson,
cond:{
in:〔
this,
field
〕
}
}
},
}},
{project:{name:1,lessons:1,sizeOflesson:{size:lessons}}},
{match:{sizeOflesson:{gt:0}}}
〕)
查询选修课包含〔Chemical,Biology,Math〕的同学。
SPL脚本:
脚本说明:
A1:定义查询条件科目数组。
A2:连接mongodb数据库。
A3:获取student表中的数据。
A4:查询存在数组中的科目记录。
A5:生成字段为name,lesson的新序表,其中符合条件的值存放在字段lesson中
A6:关闭数据库连接。
集算器对给定数组中查询记录的实现更简明易懂。
12。关联表中的数组查找
从关联表记录数据组中查找符合条件的记录,用给定的字段组合成新表。
测试数据:
Mongo脚本
db。users。aggregate(〔
{lookup:{
from:workouts,
localField:workouts,
foreignField:id,
as:workoutDocumentsArray
}},
{project:{id:0,workouts:0}},
{unwind:workoutDocumentsArray},;
{replaceRoot:{newRoot:{mergeObjects:〔ROOT,workoutDocumentsArray〕}}},
{project:{workoutDocumentsArray:0}}
〕)。pretty()
把关联表users,workouts查询结果放到数组中,再将数组拆解,提升子记录的位置,去掉不需要的字段。
SPL脚本:
脚本说明:
A1:连接mongodb数据库。
A2:获取users表中的数据。
A3:获取workouts表中的数据。
A4:查询序表A3的id值存在于序表A2中workouts数组的记录,并追加name字段,返回合并的序表。
A5:关闭数据库连接。
由于需要获取序列的交集不为空为条件,故将id转换成序列。
Mongo存储的数据结构相对关联数据库更复杂、更灵活,其提供的查询语言也非常强、能适应不同的情况,需要了解函数也不少,函数之间的结合更是变化无穷,因此要掌握并熟悉应用它并非易事。集算器的离散性、易用性恰好能弥补Mongo这方面的不足,它降低了mongo学习成本及使用mongo操作的复杂度、难度,让mongo的功能得到更充分的展现,同时也希望mongo越来越受到广大爱好者的青睐。
历史上洋务运动中慈禧真的是保守派吗洋务运动,在历史上有着非常重要的作用,是清朝末期为了学习西方的先进技术,来提高自身和抵抗外敌所做的很大的努力。但是在学习洋务运动的相关知识的时候,基本上都会把慈禧太后划在保守派……
真小气原创真小气我在菜市正买芹菜,一哥们也来买。呵呵,这伙计可真快,来得晚,可先称上了。女老板说:称可高高的啊,两块一。两块!这家伙递过两块钱。那可不行!女老板不乐意,刚学做……
古代刑罚一丈红惩罚后宫嫔妃打到血肉模糊为止在我国古代皇帝的后宫中用于妃子的刑法非常多,比如我们熟知的一丈红,在电视中经常是有出现,还有像比较残忍的铁裙之刑也是其中之一,也都是属于女子妇刑的一种,但是一丈红是多用于特用来……
每个家庭都是个逗笑大本营1、还记得前几年,偷偷拿爸爸手机开通QQ会员,突然手机被爸爸拿了回去。只见信息回复到:你即将订制QQ会员,回复任意内容将订制,不回复则不定制。我爸果断回复了一个:不……
难以置信地球至今无法解释事件北欧海盗之剑被视为神导语:我们人类赖以生存的家园地球,其实并不像我们表面看到的那样,在球上也有很多让人无法解释的谜团。随着科学的不断进步和发展,人类对于谜团也在慢慢揭开神秘面纱。接下来呢就由探秘志……
世界十大快要灭绝的动物第六仅剩只第二视力极好导语:我们无法想象一个没有动物的星球,在这个星球上生活的动物自古以来对人类是非常有用的。你们知道地球上快要灭绝的动物有哪些吗?之前小编为大家讲解过世界十大奇特的动物,下面就为大……
一杯茶品人生沉浮一甜二苦三回味人生如茶,第一道苦如生命,第二道香似爱情,第三道淡如清风,作家三毛说。清清灵灵一撮茶泡在水中,焕如积雪,烨若春敷,顿时沁人心脾的清香味弥漫了整间小屋。端杯看那水面上起伏旋转的嫩……
好的经理人要借助团队管理团队管理团队的能力非常重要。最近一本书中提到伟大领导人3大必备技能,其中第一条就是管好团队。所谓管好团队,是指建立一支真正的团队,并实现借助团队管理团队。顺带一提,另外两大技能分别……
如何正确使用防晒霜首先使用洗面奶清洗脸部,然后再用保湿水给肌肤补充水分,接着再涂抹精华素,最后再使用防晒霜。接下来就和大家详细讲解一下。正确使用防晒霜01:hr清洁皮肤在使用防……
蜂蜜玫瑰凉粽的做法你学会了吗aclasstaghrefwiki10732IaVM62E25。html蜂蜜a玫瑰凉粽非常好吃,接下来我们就来讲一讲蜂蜜玫瑰凉粽的做法。操作方法01:hr蜂蜜玫瑰凉……
年同步小康驻村年终述职报告2018年同步小康驻村年终述职报告2018年4月份,根据安排,我被派到四和村开展同步小康驻村工作,严格按照上级部门提出的下得去、呆得住、干得好的要求,认真履行一宣六帮工作……
物业上半年总结第一篇:物业上半年总结范文一、上半年工作总结;1继续健全公司各项规章制度,进一步提高公司规范化运作水平;在公司原有制度的基础上,完善了《12小时工作制》、《文……
破茧成蝶我家并不富裕,几斤米,几颗白菜,便是一天的食物。但因为是独女,父母格外疼爱我,视我为掌上明珠。不知从何时起,我爱上了跳舞,是一种几近疯狂的状态。当我和母亲说起这件事……
礼物每当我过生日时,妈妈总会送我一个非常好的礼物,今年肯定也不会列外。再过几天我的生日就要到了,那天晚上,我躺在床上有点渴,就出来喝水。偶然,听到了他们的对话,老爸无精打采地……
那片海海,是地球的生命之源,这让我对它十分好奇。从柔和优雅到暴戾无比,海的脾气阴晴不定,这又使人们十分害怕。然而,每当提到海,我心中总是涌起一股敬意。小时候,我经常翻开一些有关……
大自然的启示大自然很美妙,它给我们带来许许多多的启示。就比如蚂蚁搬运食物。阳光明媚的春天,一大早我就从家里拿了面包屑扔在地上引诱小蚂蚁。不一会儿,只见几只小小的蚂蚁从它们家里走了出来……
一份特别的礼物礼物是一缕冬日的阳光,温暖着人们的心田;礼物是一丝柔柔的春风,吹走了心中的烦恼;礼物是一条涓涓的溪流,唱响了深情的赞歌;礼物是一杯芬芳的美酒,陶醉了人们的生活。记得那次生……
课间的游戏校园里,有一颗颗跳动、热情而又澎湃的心,有一张张洋溢着青春的笑脸。校园的生活正为我们的人生之歌编织着动人的前奏。课间是曲中的音符,在校园生活这张乐谱上欢乐地跳跃着。同学们……
将跑步进行到底唉!又是体育课,又得跑步了。我迈着沉重的步伐,似乎脚里灌了铅似的抬也抬不起来,我低着头,叹着气,一路缓慢地走到操场,然后,上课铃便响了起来,真想课间再久一些啊!老师……
我家的小金鱼为什么?为什么?我心里不停地想着,为什么金鱼都死了呢?那个星期六,正是我的生日。爸爸送了我两条小金鱼,我非常喜欢。于是,我找了水草和漂亮的小石头放在了鱼缸里,加了些清水,……
美丽的赣江我的家乡在江西南昌,那里有许多名胜古迹,滕王阁、绳金塔和八大山人。也有许多美丽的风景。最美的就数赣江。那是一条十分清澈的河流。从江面看它清澈而深邃,深得透彻却看不清江底的样子。……
可爱的小猫我喜欢的动物有小狗、小仓鼠、小乌龟但我最喜欢的还是我家的小猫。小猫的身上长满了金黄色的毛,摸起来毛茸茸的,它有一对像雷达一样灵敏的耳朵,一双如黑珍珠一般明亮的眼睛圆溜溜的……
这件事发生在那年暑假去年暑假发生了一件事,时间已过去一年有余,可至今回想起来仍令我心有余悸。那是一个晴朗的下午,夏日阳光火辣辣的照在身上,真热啊!就算这样仍未阻止我和小伙伴们出去玩耍的脚步。……
大自然的声音早上,太阳出来了,碧空如洗,万里无云。心情格外舒畅。吃过早餐后,我一个人走进了公园里的树林,刚一进树林就感觉到了大自然的气息。我走向一片荷花池,听见了一片呱呱的声音,我想一定是……