Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB中的$unwind操作符是什么?_Mongodb_Aggregation Framework - Fatal编程技术网

MongoDB中的$unwind操作符是什么?

MongoDB中的$unwind操作符是什么?,mongodb,aggregation-framework,Mongodb,Aggregation Framework,这是我在MongoDB的第一天,请与我轻松相处: 我不能理解$unwind操作符,可能是因为英语不是我的母语 db.article.aggregate( { $project : { author : 1 , title : 1 , tags : 1 }}, { $unwind : "$tags" } ); 项目操作员是我能理解的,我想这就像选择一样,不是吗?。但是,$unwind QUOTING会为每个源文档中的unwi

这是我在MongoDB的第一天,请与我轻松相处:

我不能理解$unwind操作符,可能是因为英语不是我的母语

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);
项目操作员是我能理解的,我想这就像选择一样,不是吗?。但是,$unwind QUOTING会为每个源文档中的unwind数组的每个成员返回一个文档

这是一个连接吗?如果是,如何将带有_id、author、title和tags字段的$project的结果与tags数组进行比较

注意:我从MongoDB网站上取了这个例子,我不知道标签数组的结构。我认为这是一个简单的标记名数组。

$unwind将复制管道中的每个文档,每个数组元素复制一次


因此,如果您的输入管道包含一个带有两个标记元素的项目文档,{$unwind:'$tags'}会将管道转换为两个项目文档,它们除了tags字段外是相同的。在第一个文档中,标记将包含原始文档数组中的第一个元素,在第二个文档中,标记将包含第二个元素。

首先,欢迎使用MongoDB

需要记住的是,MongoDB采用了NoSQL方法来存储数据,所以从您的头脑中消除选择、连接等想法。它存储数据的方式是以文档和集合的形式,这允许动态地添加数据并从存储位置获取数据

也就是说,为了理解$unwind参数背后的概念,您首先必须理解您试图引用的用例所说的内容。来自的示例文档如下所示:

{
 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允许您为每个元素剥离一个文档并返回结果文档。 在经典方法中考虑这一点,它将等效于为标记数组中的每个项返回一个仅包含该项的文档

因此,运行以下操作的结果是:

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
}
{ "_id" : 1, "item" : "ABC", "sizes": [ "S", "M", "L"] }
{ "_id" : 2, "item" : "EFG", "sizes" : [ ] }
{ "_id" : 3, "item" : "IJK", "sizes": "M" }
{ "_id" : 4, "item" : "LMN" }
{ "_id" : 5, "item" : "XYZ", "sizes" : null }
请注意,结果数组中唯一发生变化的是tags值中返回的内容。如果你需要一个额外的参考如何工作,我已经包括了一个链接。希望这会有所帮助,祝您好运,进入我迄今为止遇到的最好的NoSQL系统之一

让我们通过一个例子来理解它

这是公司文档的外观:

$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"
    } }
])
生成包含金额和年份数组的文档

因为我们正在访问融资轮次数组中每个元素的募集金额和资助年份。为了解决这个问题,我们可以在这个聚合管道中的项目阶段之前包含一个展开阶段,并通过说我们要展开融资回合数组来参数化它:


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\u rounds数组元素的文档生成一个输出文档。现在,在这个例子中,我们的值是字符串。但是,不管数组中元素的值的类型如何,unwind都会为这些值中的每一个生成一个输出文档,这样讨论中的字段将只有该元素。在资金周转的情况下,该元素将是这些文档中的一个,作为传递到项目阶段的每个文档的资金周转值。运行这个程序的结果是,现在我们得到了一个数量和一年。我们收集的每一家公司的每一轮融资都有一个。这意味着我们的匹配产生了许多公司文档,而这些公司文档中的每一个都会产生许多文档。每个公司文件中的每轮融资各一个。“展开”使用从匹配阶段传递给它的文档执行此操作。然后每个公司的所有这些文件都被传递到项目阶段

因此,在查询示例中,出资人是Greylock的所有文档都将被拆分为多个文档,等于每个公司匹配过滤器$match:{funding_rounds.investments.financial_org.permalink:Greylock}的融资轮数。然后,每个生成的文档都将传递给我们的项目。现在,unwind为它作为输入接收的每个文档生成一个精确的副本。所有字段都有相同的键和值,但有一个例外,那就是,在
stead的值是一个单独的文档,它是一个单独的融资回合。因此,一家拥有4轮融资的公司将需要创建4个文档。其中,每个字段都是一个精确的副本,但“资金周转”字段除外,该字段将不是这些副本的数组,而是当前正在处理的公司文档中“资金周转”数组中的单个元素。因此,退绕的效果是向下一阶段输出的文档比作为输入接收的文档多。这意味着我们的项目阶段现在得到了一个funding_rounds字段,它不是数组,而是一个嵌套文档,具有一个raised_amount和funded_year字段。因此,project将为每个符合筛选条件的公司接收多个文档,因此可以单独处理每个文档,并确定每个公司每轮融资的金额和年份。

让我以与RDBMS相关的方式进行解释。声明如下:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);
适用于文件/记录:

$project/Select只返回这些字段/列作为

从文章中选择作者、标题、标签

下一个是Mongo的有趣部分,考虑这个数组标签:[有趣,好,有趣],因为另一个相关的表不能是查找/引用表,因为值有一些重复名为标签。请记住,SELECT通常会生成垂直的内容,因此展开标记就是垂直拆分为表标记

$project+$REWIND的最终结果:

将输出转换为JSON:

{ "author": "bob", "title": "this is my title", "tags": "fun"},
{ "author": "bob", "title": "this is my title", "tags": "good"},
{ "author": "bob", "title": "this is my title", "tags": "fun"}
因为我们没有告诉Mongo省略_id字段,所以它是自动添加的

关键是使其像表一样执行聚合


根据mongodb官方文件:

$unwind从输入文档解构数组字段,以输出每个元素的文档。每个输出文档都是输入文档,数组字段的值由元素替换

通过基本示例进行说明:

收款清单包含以下文档:

{
     "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
}
{ "_id" : 1, "item" : "ABC", "sizes": [ "S", "M", "L"] }
{ "_id" : 2, "item" : "EFG", "sizes" : [ ] }
{ "_id" : 3, "item" : "IJK", "sizes": "M" }
{ "_id" : 4, "item" : "LMN" }
{ "_id" : 5, "item" : "XYZ", "sizes" : null }
以下$unwind操作是等效的,并为sizes字段中的每个元素返回一个文档。如果sizes字段未解析为数组,但未丢失、为null或为空数组,$unwind将非数组操作数视为单元素数组

db.inventory.aggregate( [ { $unwind: "$sizes" } ] )

以上查询输出:

{ "_id" : 1, "item" : "ABC", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "sizes" : "L" }
{ "_id" : 3, "item" : "IJK", "sizes" : "M" }
为什么需要它

$unwind在执行聚合时非常有用。它将复杂/嵌套文档分解为简单文档,然后再执行排序、搜索等各种操作

要了解有关$REWIND的更多信息,请执行以下操作:

要了解有关聚合的更多信息,请执行以下操作:


考虑下面的例子来理解这一点 集合中的数据

{
        "_id" : 1,
        "shirt" : "Half Sleeve",
        "sizes" : [
                "medium",
                "XL",
                "free"
        ]
}
Query-db.test1.aggregate[{$unwind:$size}]

输出

{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "medium" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "XL" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "free" }

使用相同的文档会更好。作为$unwind的第一个用例,我有一组非常复杂的嵌套集。在mongo docs和stackowerflow之间,您的回答最终帮助我更好地理解了$project和$unwind。谢谢@Zameer!或者从另一个角度来看,如果标签是一个嵌入的文档,我该怎么做呢。比如$summary.tags…然后我想删除DUP并计算$size。非常感谢您的解释