MongoDB中的$unwind运算符是什么?

142

这是我使用 MongoDB 的第一天,请温柔点 :)

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

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);
项目操作符我可以理解,就像SELECT一样,对吧?但是,$unwind(引用)将在每个源文档中展开的数组成员返回一个文档
这是否类似于JOIN?如果是,那么带有_idauthortitletags字段的$project的结果如何与tags数组进行比较?
注:我从MongoDB网站上选了一个例子,我不知道tags数组的结构。我认为它是一个简单的标签名称数组。
5个回答

329

需要记住的是,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 }
}

请注意,tags实际上是一个由3个项组成的数组,本例中为“fun”,“good”和“fun”。

$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 值更改了。如果您需要有关此操作方式的其他参考资料,请查看此链接:here


1
如果 "tags" 是一个嵌套文档,我该如何处理呢?例如 $summary.tags... 我想去重并统计 $size。 - chovy
1
非常感谢您的解释。 - M.N. Waleedh

55

$unwind 对管道中的每个数组元素都会复制一遍文档。

所以,如果您的输入管道包含一个具有两个元素的tags数组的文章文档,{$unwind:'$tags'} 会将管道转换为两个相同的文章文档,除了 tags字段。在第一个文档中,tags将包含原始文档数组中的第一个元素,在第二个文档中,tags将包含第二个元素。


18

考虑以下示例以了解这个概念。 集合中的数据

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

查询 -- db.test1.aggregate( [ { $unwind : "$sizes" } ] );

输出

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

6
根据mongodb官方文档: $unwind操作符可以将输入文档中的数组字段展开,每个元素都会生成一个新文档。新文档中,该数组字段的值被替换成该元素。
下面通过一个基本示例进行解释:
假设一个inventory集合包含以下文档:
{ "_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字段未解析为数组但不缺失、空值或空数组,则$unwind将非数组操作数视为单个元素数组。
db.inventory.aggregate( [ { $unwind: "$sizes" } ] )

或者

db.inventory.aggregate( [ { $unwind: { path: "$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?

$unwind 在聚合操作中非常有用。它可以将复杂/嵌套的文档拆分为简单的文档,然后执行各种操作,例如排序、搜索等。

了解更多关于 $unwind 的信息:

https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

了解更多关于聚合操作的信息:

https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/


4

让我以与关系型数据库相关的方式来解释。这是该语句:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

申请 文件/记录

{
 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 }
}

$project / Select 只是返回以下字段/列:

SELECT 作者, 标题, 标签 FROM 文章

接下来是Mongo的有趣部分,将这个数组 tags : [ "fun" , "good" , "fun" ] 视为另一个相关表(不能是查找/引用表,因为值有一些重复)命名为“tags”。记住,SELECT通常会垂直生成结果,所以展开“tags”就是要将其垂直分成表格“tags”。

$project + $unwind 的最终结果为: enter image description here

将输出转换为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"字段,所以它会自动添加。
关键是将其制作成表格形式以执行聚合。

另一种思考方式是使用UNION ALL。 - Jeb50

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接