MongoDB 中的 $unwind 运算符是啥?

Posted

技术标签:

【中文标题】MongoDB 中的 $unwind 运算符是啥?【英文标题】:What's the $unwind operator in MongoDB?MongoDB 中的 $unwind 运算符是什么? 【发布时间】:2013-05-03 03:01:40 【问题描述】:

这是我使用 MongoDB 的第一天,所以请放轻松:)

我听不懂$unwind 运算符,可能是因为英语不是我的母语。

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

项目运营商是我可以理解的,我想(就像SELECT,不是吗?)。但是随后,$unwind(引用)为每个源文档中展开数组的每个成员返回一个文档

这像JOIN 吗?如果是,如何将$project(带有_idauthortitletags 字段)的结果与tags 数组进行比较?

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

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

【参考方案2】:

首先,欢迎来到 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

请注意,结果数组中唯一改变的是标签值中返回的内容。如果您需要有关其工作原理的其他参考,我提供了一个链接 here。希望这对您有所帮助,并祝您在尝试我迄今为止遇到的最好的 NoSQL 系统之一时好运。

【讨论】:

如果标签是嵌入式文档,我将如何做到这一点。比如$summary.tags....然后我想删除重复并计算$size。 非常感谢您的解释【参考方案3】:

让我以一种与 RDBMS 相关的方式进行解释。这是声明:

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 通常会产生垂直的东西,因此展开“标签”是将 split() 垂直地拆分为表格“标签”。

$project + $unwind 的最终结果:

将输出转换为 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【参考方案4】:

根据 mongodb 官方文档:

$unwind 从输入文档中解构一个数组字段,为每个元素输出一个文档。每个输出文档都是输入文档,其中数组字段的值被元素替换。

通过基本示例进行说明:

收集清单具有以下文件:

 "_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 字段中的每个元素返回一个文档。如果 size 字段未解析为数组但未丢失、null 或空数组,则 $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 的更多信息:

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

要了解有关聚合的更多信息:

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

【讨论】:

【参考方案5】:

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


        "_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" 

【讨论】:

以上是关于MongoDB 中的 $unwind 运算符是啥?的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB Aggregation - $unwind order 文档是不是与嵌套数组 order 相同

使用 $unwind、$lookup 和 $group 的复杂聚合中的 mongodb 正确列表顺序

MongoDB 操作符 $unwind 展开数组(agregation)

mongoDB实战聚合管道--$unwind

mongodb aggregate $unwind

MongoDB——聚合管道之$unwind操作