这是我与MongoDB的第一天,所以请跟我一起轻松:)
我无法理解$unwind
操作员,也许是因为英语不是我的母语.
db.article.aggregate( { $project : { author : 1 , title : 1 , tags : 1 }}, { $unwind : "$tags" } );
我想项目操作员是我能理解的(就像SELECT
是,不是吗?).但是,$unwind
(引用)为每个源文档中的展开数组的每个成员返回一个文档.
这是一个JOIN
吗?如果是,如何的结果$project
(有_id
,author
,title
和tags
字段)可以用比较tags
阵列?
注意:我从MongoDB网站上采用了这个例子,我不知道tags
数组的结构.我认为这是一个简单的标签名称数组.
首先,欢迎来到MongoDB!
需要记住的是MongoDB采用"NoSQL"方法进行数据存储,因此会消除您心中的选择,联接等想法.它存储数据的方式是以文档和集合的形式,这允许动态方式从存储位置添加和获取数据.
话虽如此,为了理解$ unwind参数背后的概念,您首先必须了解您尝试引用的用例是什么.mongodb.org的示例文档如下:
{ title : "this is my title" , author : "bob" , posted : new Date () , pageViews : 5 , tags : [ "fun" , "good" , "fun" ] , comments : [ { author :"joe" , text : "this is cool" } , { author :"sam" , text : "this is bad" } ], other : { foo : 5 } }
注意标签实际上是3个项目的数组,在这种情况下是"有趣","好"和"有趣".
$ unwind的作用是允许您为每个元素剥离文档并返回生成的文档.要以经典的方法来考虑这一点,它将是"对于tags数组中的每个项目,仅返回仅包含该项目的文档"的等效项.
因此,运行以下结果:
db.article.aggregate( { $project : { author : 1 , title : 1 , tags : 1 }}, { $unwind : "$tags" } );
将返回以下文件:
{ "result" : [ { "_id" : ObjectId("4e6e4ef557b77501a49233f6"), "title" : "this is my title", "author" : "bob", "tags" : "fun" }, { "_id" : ObjectId("4e6e4ef557b77501a49233f6"), "title" : "this is my title", "author" : "bob", "tags" : "good" }, { "_id" : ObjectId("4e6e4ef557b77501a49233f6"), "title" : "this is my title", "author" : "bob", "tags" : "fun" } ], "OK" : 1 }
请注意,结果数组中唯一更改的内容是在tags值中返回的内容.如果您需要有关其工作方式的其他参考,我在此处添加了一个链接.希望这对您进入迄今为止遇到的最好的NoSQL系统之一有所帮助,并祝您好运.
$unwind
复制管道中的每个文档,每个数组元素一次.
因此,如果您的输入管道包含一个包含两个元素的文章doc tags
,{$unwind: '$tags'}
则会将管道转换为两个文章文档,除了tags
字段之外是相同的.在第一个doc中,tags
将包含原始doc的数组中的第一个元素,而在第二个doc中,tags
将包含第二个元素.
让我们通过一个例子来理解它
这就是公司文档的样子:
将$unwind
允许我们采取文档作为输入的是有一个数组值字段并产生输出文档,使得有一个为阵列中的每个元件一个输出文档.资源
让我们回到我们公司的例子,看看展开阶段的使用.这个查询:
db.companies.aggregate([
{ $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
{ $project: {
_id: 0,
name: 1,
amount: "$funding_rounds.raised_amount",
year: "$funding_rounds.funded_year"
} }
])
生成包含金额和年份数组的文档.
因为我们正在获得资金回合阵列中每个要素的筹集金额和资助年度.要解决这个问题,我们可以在此聚合管道中的项目阶段之前包含一个展开阶段,并通过说我们想要unwind
资金回合数组来参数化:
db.companies.aggregate([
{ $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
{ $unwind: "$funding_rounds" },
{ $project: {
_id: 0,
name: 1,
amount: "$funding_rounds.raised_amount",
year: "$funding_rounds.funded_year"
} }
])
如果我们查看funding_rounds
数组,我们知道每个数组funding_rounds
都有一个raised_amount
和一个funded_year
字段.因此,unwind
对于作为funding_rounds
数组元素的每个文档,都会生成输出文档.现在,在这个例子中,我们的值是string
s.但是,无论数组中元素的值类型如何,unwind
都会为这些值中的每一个生成一个输出文档,这样所讨论的字段就只有该元素.在这种情况下funding_rounds
,该元素将是这些文档中的一个,作为funding_rounds
传递到我们project
舞台的每个文档的值.结果,然后运行这个,现在我们得到一个amount
和一个year
.一个用于每一轮融资,每家公司我们收藏.这意味着我们的比赛产生了许多公司文件,而这些公司文件中的每一个都会产生许多文件.每个公司文件中的每个资金回合一个.unwind
使用从match
舞台传递给它的文件执行此操作.然后,每个公司的所有这些文件都会传递到project
舞台上.
因此,资助者是Greylock的所有文档(如查询示例中)将被分成许多文档,等于每个匹配过滤器的公司的资金轮数$match: {"funding_rounds.investments.financial_org.permalink": "greylock" }
.然后每个结果文件将被传递给我们project
.现在,unwind
为它作为输入接收的每个文档生成一个精确的副本.所有字段都具有相同的键和值,但有一个例外,那就是funding_rounds
字段而不是funding_rounds
文档数组,而是具有单个文档的值,这是一个单独的资金回合.因此,拥有4轮融资的公司将unwind
产生4个文件.除了funding_rounds
字段之外,每个字段都是精确副本,而不是每个字段的数组,而是来自当前正在处理funding_rounds
的公司文档的数组中的单个元素unwind
.因此,unwind
具有输出到下一阶段的文档比输入的文档更多的效果.这意味着我们的project
舞台现在funding_rounds
再次得到一个字段,不是一个数组,而是一个具有a raised_amount
和a funded_year
字段的嵌套文档.因此,project
将为每个公司收到match
过滤器的多个文档,因此可以单独处理每个文档,并为每个公司的每个资金轮次确定单独的金额和年份.