玩转Mongo计算

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. 单表内嵌数组结构的统计

对嵌套数组结构中的数据统计处理。查询考试科目的平均分及每个学生的总成绩情况。

测试数据: _idnamesexScroe1TomF

[{"lesson":" Physics ","mark":60 },
{"lesson":" Chemical ","mark":72 }]

2JerryM

[{"lesson":" Physics ","mark":92 },
{"lesson":" Math ","mark":81 }]

期待统计结果: Physics76

Tom132Chemical72

Jerry173Math81



脚本:

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 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"student.find()").fetch()

3=A2.conj(scroe).groups(lesson:LESSON;avg(mark):AVG)

4=A2.new(name:NAME,scroe.sum(mark):TOTAL)

5>A1.close()

按课目统计的总分数

LESSONAVGChemical72.0Math81.0Physics76.0

每个学生的总成绩

NAMETOTALTom132Jerry173

脚本说明:
A1:连接 mongo 数据库。
A2:获取 student 表中的数据。
A3:将 scroe 数据合并成序表,再按课程分组,计算平均分。
A4:统计每个学生的成绩后返回列名为 NAME、TOTAL 的序表。new 函数表示生成新序表。
A5:关闭数据库连接。

这个比较常用嵌套结构统计的例子许多人遭遇过、需要先拆解,主要是熟悉 mongodb 对嵌套数据结构的处理。

2. 单表内嵌文档求和

对内嵌文档中的数据求和处理, 下面要统计每条记录的 income,output 的数量和。

测试数据: _idincomeoutput1{"cpu":1000, "mem":500, "mouse":"100"}{"cpu":1000, "mem":600 ,"mouse":"120"}2{"cpu":2000, "mem":1000,

"mouse":"50","mainboard":500 }{"cpu":1500, "mem":300 }

期待统计结果

_idincomeoutput116001720235501800

Mongodb脚本:

var fields = [ "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 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"computer.find()").fetch()

3=A2.new(_id:ID,income.array().sum():INCOME,output.array().sum():OUTPUT)

4>A1.close()

统计结果

IDINCOMEOUTPUT11600.01720.023550.01800.0

脚本说明:
A1:连接数据库
A2:获取 computer 表中的数据
A3:将 income、output 字段中的数据分别转换成序列求和,再与 ID 组合生成新序表
A4:关闭数据库连接。

获取子记录的字段值,然后求和,相对于 mongo 脚本简化了不少。这个内嵌文档与内嵌数组在组织结构上有点类似,不小心容易混淆,注意与上例中的 scroe 数组结构比较,写出的脚本有所不同。

3. 分段分组结构

统计各段内的记录数量。下面按销售量分段,统计各段内的数据量,数据如下: _idNAMESTATESALES1AshleyNew York110002RachelMontana90003EmilyNew York88004MatthewTexas80005AlexisIllinois14000

分段方法:0-3000;3000-5000;5000-7500;7500-10000;10000 以上。

期望结果:

Segmentnumber3342

Mongo 脚本

var a_count=0;
var b_count=0;
var c_count=0;
var d_count=0;
var e_count=0;
db.sales.find({

}).forEach(
function(myDoc) {
if (myDoc.SALES <3000) {
a_count += 1;
}
else if (myDoc.SALES <5000) {
b_count += 1;
}
else if (myDoc.SALES <7500) {
c_count += 1;
}
else if (myDoc.SALES <10000) {
d_count += 1;
}
else {
e_count += 1;
}
}
);

print("a_count="+a_count)
print("b_count="+b_count)
print("c_count="+c_count)
print("d_count="+d_count)
print("e_count="+e_count)

这个需求按条件分段分组,mongodb 没有提供对应的 api,实现起来有点繁琐,上面的程序是其中实现的一个例子参考,当然也可以写成其它实现形式。下面看看集算器脚本的实现。

SPL 脚本:

AB1[3000,5000,7500,10000,15000]

2=mongo_open("mongodb://127.0.0.1:27017/raqdb")

3=mongo_shell(A2,"sales.find()").fetch()

4=A3.groups(A1.pseg(int(~.SALES)):Segment;count(1): number)

5>A2.close()

脚本说明:

A1:定义 SALES 分组区间。

A2:连接 mongodb 数据库。

A3:获取 sales 表中的数据。

A4:根据 SALES 区间分组统计员工数。其中函数 pseg()表示返回成员在序列中的区段序号,int() 表示转换成整数。

A5:关闭数据库连接。


pseg 的使用让 SPL 脚本精简了不少。

4. 同构表合并

具有相同结构的多表数据合并。下面将两个员工表数据合并。

Emp1:_idNAMESTATEHIREDATEDEPTSALARY1AshleyNew York2008-03-16Finance110002RachelMichigan2001-04-16Sales90003EmilyNew York2011-07-11HR88004MatthewTexas2003-03-06R&D80005AlexisIllinois2008-03-10Sale14000Emp2:

_idNAMESTATEHIREDATEDEPTSALARY10JacobNew York2009-03-14Sales1300012JessicaFlorida2011-04-19Sales950013DanielNew York2001-02-11HR780014AlyssaMontana2013-09-06R&D800015HannahFlorida2015-06-10Sales12500

合并数据结果:

_idNAMESTATEHIREDATEDEPTSALARY1AshleyNew York2008-03-16Finance110002RachelMichigan2001-04-16Sales90003EmilyNew York2011-07-11HR88004MatthewTexas2003-03-06R&D80005AlexisIllinois2008-03-10Sale1400010JacobNew York2009-03-14Sales1300012JessicaFlorida2011-04-19Sales950013DanielNew York2001-02-11HR780014AlyssaMontana2013-09-06R&D800015HannahFlorida2015-06-10Sales12500

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 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"emp1.find()").fetch()

3=mongo_shell(A1,"emp2.find()").fetch()

4=A2|A3

5>A1.close()

脚本说明:
A1:连接 mongodb 数据库。
A2:获取 emp1 表中的数据。
A3:获取 emp2 表中的数据。
A4:合并两表数据。
A5:关闭数据库连接。

熟悉 sql 语句的 mongo 初学者面对数据合并的 mongo 脚本,估计首次遇到时有点“懵”,SPL 脚本就显得自然易懂了。

5. 关联嵌套结构情况 1

两个关联表,表 A 与表 B 中的内嵌文档信息关联, 且返回的信息在内嵌文档中。表 childsgroup 字段 childs 是嵌套数组结构,需要合并的信息 name 在其下。

history :

_ididHistorychild_id1001today workedch0012002Workingch0043003now workingch009

childsgroup :

_idgroupidnamechilds1g001group1{"id":"ch001","info":{"name":"a"}},{"id":"ch002","info":{"name":"b"}}2g002group1{"id":"ch004","info":{"name":"c"}},{"id":"ch009","info":{"name":"d"}}

表History中的child_id与表childsgroup中的childs.id关联,希望得到下面结果:
{
“_id” : ObjectId(“5bab2ae8ab2f1bdb4f434bc3”),
“id” : “001”,
“history” : “today worked”,
“child_id” : “ch001”,
“childInfo” :
{
“name” : “a”
}
………………
}

Mongo 脚本

db.history.aggregate([
{$lookup: {
from: "childsgroup",
let: {child_id: "$child_id"},
pipeline: [
{$match: { $expr: { $in: [ "$$child_id", "$childs.id"] } } },
{$unwind: "$childs"},
{$match: { $expr: { $eq: [ "$childs.id", "$$child_id"] } } },
{$replaceRoot: { newRoot: "$ childs.info "} }
],
as: "childInfo"
}},
{"$unwind": "$childInfo"}
])

这个脚本用了几个函数lookup、pipeline、match、unwind、replaceRoot处理,一般 mongodb 用户不容易写出这样复杂脚本;那我们再看看 spl 脚本的实现:

SPL 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"history.find()").fetch()

3=mongo_shell(A1,"childsgroup.find()").fetch()

4=A3.conj(childs)

5=A2.join(child_id,A4:id,info.name:name)

6>A1.close()

关联查询结果:

_ididhistorychild_idname1001today workedch001a2002workingch004c3003now workingch009d 脚本说明:

A1:连接 mongodb 数据库。

A2:获取 history 表 中的数据。

A3:获取 childsgroup 表 中的数据。

A4:将 childsgroup 中的 childs 数据提取出来合并成序表。

A5:表 history 中的 child_id 与表 childs 中的 id 关联查询,追加 name 字段, 返回序表。

A6:关闭数据库连接。

相对 mongodb 脚本写法,SPL 脚本的难度降低了不少,省去了熟悉有关 mongo 函数的用法,如何去组合处理数据等,节约了不少时间。

6. 关联嵌套结构情况 2

两个关联表,表 A 与表 B 中的内嵌文档信息关联, 将信息合并到内嵌文档中。表 txtPost 字段 comment 是嵌套数组结构,需要把 comment_content 合并到其下。

txtComment:

_IDcomment_nocomment_content1143test test2140math

txtPost

_IDpost_noComment148[{"comment_no" : 143, "comment_group" : 1} ]247[{"comment_no" : 140, "comment_group" : 2},

{"comment_no" : 143, "comment_group" : 3} ]

期望结果:

_IDpost_noComment148[{"comment_no" : 143, "comment_group" : 1,"comment_content" : "test test"} ]247[{"comment_no" : 140, "comment_group" : 2,"comment_content" : "math"},

{"comment_no" : 143, "comment_group" : 3,"comment_content" : "test test"} ]

Mongo 脚本

db.getCollection("txtPost").aggregate([
{ "$unwind": "$comment"},
{ "$lookup": {
"from": "txtComment",
"localField": "comment.comment_no",
"foreignField": "comment_no",
"as": "comment.comment_content"
}},
{ "$unwind": "$comment.comment_content"},
{ "$addFields": { "comment.comment_content": "$comment.comment_content.comment_content"}},
{ "$group": {
"_id": "$_id",
'post_no':{"$first": "$post_no"},
"comment": {"$push": "$comment"}
}},

]).pretty()

表txtPost 按 comment 拆解成记录,然后与表 txtComment 关联查询,将其结果放到数组中,再将数组拆解成记录,将comment_content 值移到 comment 下,最后分组合并。

SPL 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"txtPost.find()").fetch()

3=mongo_shell(A1,"txtComment.find()").fetch()

4=A2.conj(comment.derive(A2.post_no:pno))

5=A4.join(comment_no,A3:comment_no,comment_content:Content)

6=A5.group(pno;~:comment)

7>A1.close()

脚本说明:

A1:连接 mongodb 数据库。

A2:获取 txtPost 表 中的数据。

A3:获取 txtComment 表 中的数据。

A4:将序表 A2 下的 comment 与 post_no 组合成序表,其中 post_no 改名为 pno。

A5:序表 A4 通过 comment_no 与序表 A3 关联,追加字段 comment_content,将其改名为 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: [ // note the subdocuments here
{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: { // add the required fields to the top level structure
"isCompleted": "$isCompleted.isCompleted",
"serialNo": "$isCompleted.serialNo",
"batchNo": "$isCompleted.batchNo"
}
}])

lookup 两表关联查询,首个 addFields获取isCompleted数组的第一个记录,后一个addFields 转换成所需要的几个字段信息

SPL 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"collection1.find()").fetch()

3=mongo_shell(A1,"collection2.find()").fetch()

4=A3.conj(A2.select(order:A3.product.order,lot:A3.product.lot).derive(A3.serialNo:sno,A3.batchNo:bno))

5>A1.close()

脚本说明:

A1:连接 mongodb 数据库。

A2:获取 collection1 表 中的数据。

A3:获取 collection2 表 中的数据。

A4:根据条件 order, lot 从序表 A2 中查询记录,然后追加序表 A3 中的字段 serialNo, batchNo,返回合并后的序表。

A5:关闭数据库连接。

实现从数据记录中的内嵌结构中筛选,将符合条件的数据合并成新序表。

8. 多字段分组统计

统计分类项下的总数及各子项数。下面统计按 addr 分类 book 数及其下不同的 book 数。 addrbookaddress1book1address2book1address1book5address3book9address2book5address2book1address1book1address15book1address4book3address5book1address7book11address1book1

期望结果:

_idTotalbooksCountaddress14book13

book51address151book11address23book12

book51address31book91address41book31address51book11address71book111

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脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"books.find()")

3=A2.groups(addr,book;count(book): Count)

4=A3.groups(addr;sum(Count):Total)

5=A3.join(addr,A4:addr,Total)

6>A1.close()

计算结果:

AddressbookCountTotaladdress1book134address1book514address15book111address2book123address2book513address3book911address4book311address5book111address7book1111

脚本说明:
A1:连接 mongodb 数据库。
A2:获取books表中的数据。
A3:按 addr,book 分组统计 book 数,
A4:再按 addr 分组统计 book 数。
A5:将 A4 中的 Total 按 addr 关联后合并到序表中。
A6:关闭数据库连接。

9. 两表关联查询

从关联表中选择所需要的字段组合成新表。

Collection1:

user1user2income120.56130.26

collection2:

user1user2output120.3130.4230.5

期望结果:

user1user2incomeoutput120.560.3130.260.4

Mongo 脚本

db.c1.aggregate([
{ "$lookup": {
"from": "c2",
"localField": "user1",
"foreignField": "user1",
"as": "collection2_doc"
}},
{ "$unwind": "$collection2_doc"},
{ "$redact": {
"$cond": [
{"$eq": [ "$user2", "$collection2_doc.user2"] },
"$$KEEP",
"$$PRUNE"
]
}},
{ "$project": {
"user1": 1,
"user2": 1,
"income": "$income",
"output": "$collection2_doc. output"
}}
]).pretty()

lookup 两表进行关联查询,redact 对记录根据条件进行遍历处理,project 选择要显示的字段。

SPL脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"c1.find()").fetch()

3=mongo_shell(A1,"c2.find()").fetch()

4=A2.join(user1:user2,A3:user1:user2,output)

5>A1.close()

脚本说明:
A1:连接 mongodb 数据库。
A2:获取c1表中的数据。
A3:获取c2表中的数据。
A4:两表按字段 user1,user2 关联,追加序表 A3 中的 output 字段,返回序表。
A5:关闭数据库连接。

通过 join 把两个关联表不同的字段合并成新表。

10. 多表关联查询

多于两个表的关联查询,结合成一张大表。

Doc1:

_idfirstNamelastNameU001shubhamverma

Doc2:

_iduserIdaddressmob2U001Gurgaon9876543200

Doc3:

_iduserIdfbURLstwitterURLs3U001 facebook.comhttp ://www.twitter.com

合并后的结果:
{
"_id" : ObjectId("5901a4c63541b7d5d3293766"),
"firstName" : "shubham",
"lastName" : "verma",

"address" : {
"address" : "Gurgaon"
},
"social" : {
"fbURLs" : " facebook.com ",
"twitterURLs" : " 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 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"doc1.find()").fetch()

3=mongo_shell(A1,"doc2.find()").fetch()

4=mongo_shell(A1,"doc3.find()").fetch()

5=A2.join(_id,A3:userId,address,mob)

6=A5.join(_id,A4:userId,fbURLs,twitterURLs)

7>A1.close()

此脚本与上面例子类似,只是多了一个关联表,每次 join 就新增加字段,最后叠加构成一张大表。.

SPL 脚本的简洁性、统一性就非常明显。

11. 指定数组查找

从指定的数组中查找符合条件的记录。所给的数组为:["Chemical", "Biology", "Math"]。

测试数据:

_idNameLesson1jacker[English, Chemical,Math, Physics]2tom[Chinese, Chemical,Math, Biology]3Mint[Chinese,History]

期望结果:

_idNameLesson1Jacker[Chemical,Math]2Tom[Chemical,Math,Biology]

Mongodb 脚本

var field = ["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 脚本:

AB1[Chemical, Biology, Math]

2=mongo_open("mongodb://127.0.0.1:27017/raqdb")

3=mongo_shell(A2,"student.find()").fetch()

4=A3.select(lesson^A1!=[])

5=A4.new(name, ~.lesson^A1)

6>A2.close()

脚本说明:
A1:定义查询条件科目数组。
A2:连接 mongodb 数据库。
A3:获取 student 表中的数据。
A4:查询存在数组中的科目记录。
A5:生成字段为 name, lesson 的新序表,其中符合条件的值存放在字段 lesson 中
A6:关闭数据库连接。

集算器对给定数组中查询记录的实现更简明易懂。

12. 关联表中的数组查找

从关联表记录数据组中查找符合条件的记录, 用给定的字段组合成新表。

测试数据:

users:

_idNameworkouts1000xxx[2,4,6]1002yyy[1,3,5]

workouts:

_idDateBook11/1/2001Othello22/2/2001A Midsummer Night's Dream33/3/2001The Old Man and the Sea44/4/2001GULLIVER’S TRAVELS55/5/2001Pickwick Papers66/6/2001The Red and the Black

期望结果:

Name_idDateBookxxx22/2/2001A Midsummer Night's Dreamxxx44/4/2001GULLIVER’S TRAVELSxxx66/6/2001The Red and the Blackyyy11/1/2001Othelloyyy33/3/2001The Old Man and the Seayyy55/5/2001Pickwick Papers

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 脚本:

AB1=mongo_open("mongodb://127.0.0.1:27017/raqdb")

2=mongo_shell(A1,"users.find()").fetch()

3=mongo_shell(A1,"workouts.find()").fetch()

4=A2.conj(A3.select(A2.workouts^~.array(_id)!=[]).derive(A2.name))

5>A1.close()

脚本说明:

A1:连接 mongodb 数据库。

A2:获取 users 表中的数据。

A3:获取 workouts 表中的数据。

A4:查询序表 A3 的 _id 值存在于序表 A2 中 workouts 数组的记录, 并追加 name 字段, 返回合并的序表。

A5:关闭数据库连接。

由于需要获取序列的交集不为空为条件,故将 _id 转换成序列。

Mongo 存储的数据结构相对关联数据库更复杂、更灵活,其提供的查询语言也非常强、能适应不同的情况,需要了解函数也不少,函数之间的结合更是变化无穷,因此要掌握并熟悉应用它并非易事。集算器的离散性、易用性恰好能弥补 Mongo 这方面的不足,它降低了 mongo 学习成本及使用 mongo 操作的复杂度、难度,让 mongo 的功能得到更充分的展现,同时也希望 mongo 越来越受到广大爱好者的青睐。



作者:oradt

链接: c.raqsoft.com.cn/articl

来源:乾学院

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发布于 2018-11-06 09:23