【问题标题】: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数组的结构。我认为这是一个简单的标签名称数组。

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案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" }
        

        【讨论】:

          猜你喜欢
          • 2012-05-11
          • 2013-07-31
          • 1970-01-01
          • 1970-01-01
          • 2010-12-19
          • 2021-12-04
          • 2021-10-28
          • 2021-02-13
          • 2012-11-21
          相关资源
          最近更新 更多