当前位置: 首页 > 知识库问答 >
问题:

MongoDb管道聚合$展开子文档

谭刚毅
2023-03-14

我试图使用MongoDb列出展开嵌套数组。

一个产品包含任务,每个任务可以有零个、一个或多个子任务。

以下是产品文档示例:

db.products.find({_id: ObjectId("554a13d4b692088a38f01f3b")})

结果:

{
"_id" : ObjectId("554a13d4b692088a38f01f3b"),
"title" : "product title",
"order" : 3,
"description" : "Description here ",
"status" : "live",
"tasks" : [ 
    {
        "title" : "task 1",
        "description" : "task 1 desc",
        "order" : 10,
        "_id" : ObjectId("554a13d4b692088a38f01f3a"),
        "status" : "live",
        "subTasks" : [ 
            {
                "title" : "task 1 sub 1",
                "content" : "aaa",
                "order" : -2,
                "_id" : ObjectId("554a13d4b692088a38f01f5a"),
                "status" : "live"
            }, 
            {
                "title" : "task 1 sub 2",
                "content" : "aaa",
                "order" : 1,
                "_id" : ObjectId("554a13d4b692088a38f01f3a"),
                "status" : "live"
            }, 
            {
                "title" : "task 1 sub 4",
                "content" : "aaa",
                "order" : 8,
                "_id" : ObjectId("554a13d4b692088a38f01f4a"),
                "status" : "live"
            }, 
            {
                "title" : "task 1 sub 3 ",
                "content" : "aaa",
                "order" : 2,
                "_id" : ObjectId("5550d0a61662211332d9a973"),
                "status" : "live"
            }
        ]
    }, 
    {
        "title" : "task 2",
        "description" : "task desc 2",
        "order" : 1,
        "_id" : ObjectId("5550855f9ee2db4e3958d299"),
        "status" : "live",
        "subTasks" : [ 
            {
                "title" : "task 2 sub 1",
                "content" : "bbb",
                "order" : 1,
                "_id" : ObjectId("55508f459ee2db4e3958d29a"),
                "status" : "live"
            }
        ]
    }, 
    {
        "title" : "task 3",
        "description" : "task 3 desc",
        "order" : 2,
        "_id" : ObjectId("5551b844bb343a620f85f323"),
        "status" : "live",
        "subTasks" : [ 
            {
                "title" : "task 3 sub 2",
                "content" : "cccc",
                "order" : 0,
                "_id" : ObjectId("5551b88abb343a620f85f324"),
                "status" : "live"
            }, 
            {
                "title" : "task 3 sub 4",
                "content" : "cccc",
                "order" : 1,
                "_id" : ObjectId("5551b8f1bb343a620f85f325"),
                "status" : "hidden"
            }, 
            {
                "title" : "task 3 sub 3",
                "content" : "ccc",
                "order" : 2,
                "_id" : ObjectId("5551ba40bb343a620f85f327"),
                "status" : "hidden"
            }, 
            {
                "title" : "task 3 sub 1",
                "content" : "cccc",
                "order" : -1,
                "_id" : ObjectId("5551bcb8c31283c051d30b7c"),
                "status" : "hidden"
            }
        ]
    }
]}

聚合管道在对任务进行排序方面起到了很大的作用

有时任务没有子任务,例如:

{
"_id" : ObjectId("554a13d4b692088a38f01f3b"),
"title" : "product title",
"order" : 3,
"description" : "Description here ",
"status" : "live",
"tasks" : [ 
    {
        "title" : "task 1",
        "description" : "task 1 desc",
        "order" : 10,
        "_id" : ObjectId("554a13d4b692088a38f01f3a"),
        "status" : "live",
        "subTasks" : [ 
            {
                "title" : "task 1 sub 1",
                "content" : "aaa",
                "order" : -2,
                "_id" : ObjectId("554a13d4b692088a38f01f5a"),
                "status" : "live"
            }, 
            {
                "title" : "task 1 sub 2",
                "content" : "aaa",
                "order" : 1,
                "_id" : ObjectId("554a13d4b692088a38f01f3a"),
                "status" : "live"
            }, 
            {
                "title" : "task 1 sub 4",
                "content" : "aaa",
                "order" : 8,
                "_id" : ObjectId("554a13d4b692088a38f01f4a"),
                "status" : "live"
            }, 
            {
                "title" : "task 1 sub 3 ",
                "content" : "aaa",
                "order" : 2,
                "_id" : ObjectId("5550d0a61662211332d9a973"),
                "status" : "live"
            }
        ]
    }, 
    {
        "title" : "task 2",
        "description" : "task desc 2",
        "order" : 1,
        "_id" : ObjectId("5550855f9ee2db4e3958d299"),
        "status" : "live",
        "subTasks" : [ 

        ]
    }, 
    {
        "title" : "task 3",
        "description" : "task 3 desc",
        "order" : 2,
        "_id" : ObjectId("5551b844bb343a620f85f323"),
        "status" : "live",
        "subTasks" : [ 
            {
                "title" : "task 3 sub 2",
                "content" : "cccc",
                "order" : 0,
                "_id" : ObjectId("5551b88abb343a620f85f324"),
                "status" : "live"
            }, 
            {
                "title" : "task 3 sub 4",
                "content" : "cccc",
                "order" : 1,
                "_id" : ObjectId("5551b8f1bb343a620f85f325"),
                "status" : "hidden"
            }, 
            {
                "title" : "task 3 sub 3",
                "content" : "ccc",
                "order" : 2,
                "_id" : ObjectId("5551ba40bb343a620f85f327"),
                "status" : "hidden"
            }, 
            {
                "title" : "task 3 sub 1",
                "content" : "cccc",
                "order" : -1,
                "_id" : ObjectId("5551bcb8c31283c051d30b7c"),
                "status" : "hidden"
            }
        ]
    }
]
}

当他们没有孩子的时候,还有什么可以帮助他们完成任务吗?

当前聚合:

[
 {$match: {_id: ObjectId("554a13d4b692088a38f01f3b")}}, 
 {$project: {tasks: 1, doc: {title: "$title", order: "$order", description: "$description", status: "$status"}}}, 
 {$unwind: "$tasks"}, 
 {$unwind: "$tasks.subTasks"}, 
 {$sort: {"tasks.subTasks.order": 1, "tasks.order": 1}}, 
 {$project: {doc: 1, task_id: "$tasks._id", tasks_doc: {title: "$tasks.title", description: "$tasks.description", order: "$tasks.order", status: "$tasks.status"}, subTasks: "$tasks.subTasks"}}, 
 {$group: {_id: {_id: "$_id", task_id: "$task_id", doc: "$doc", task_doc: "$tasks_doc"}, subTasks: {$push: "$subTasks"}}}, 
 {$group: {_id: {_id: "$_id._id", doc: "$_id.doc"}, tasks: {$push: {_id: "$_id.task_id", title: "$_id.task_doc.title", description: "$_id.task_doc.description", order: "$_id.task_doc.order", status: "$_id.task_doc.status", subTasks: "$subTasks"}}}}, 
 {$project: {_id: "$_id._id", title: "$_id.doc.title", description: "$_id.doc.description", order: "$_id.doc.order", status: "$_id.doc.status", tasks: 1}}
]

期望的结果:

{
"_id": ObjectId("554a13d4b692088a38f01f3b"),
"title": "product title",
"order": 3,
"description": "Description here ",
"status": "live",
"tasks": [
    {
        "title": "task 2",
        "description": "task desc 2",
        "order": 1,
        "_id": ObjectId("5550855f9ee2db4e3958d299"),
        "status": "live",
        "subTasks": [

        ]
    },
    {
        "title": "task 3",
        "description": "task 3 desc",
        "order": 2,
        "_id": ObjectId("5551b844bb343a620f85f323"),
        "status": "live",
        "subTasks": [
            {
                "title": "task 3 sub 1",
                "content": "cccc",
                "order": -1,
                "_id": ObjectId("5551bcb8c31283c051d30b7c"),
                "status": "hidden"
            },
            {
                "title": "task 3 sub 2",
                "content": "cccc",
                "order": 0,
                "_id": ObjectId("5551b88abb343a620f85f324"),
                "status": "live"
            },
            {
                "title": "task 3 sub 3",
                "content": "ccc",
                "order": 2,
                "_id": ObjectId("5551ba40bb343a620f85f327"),
                "status": "hidden"
            }{
                "title": "task 3 sub 4",
                "content": "cccc",
                "order": 1,
                "_id": ObjectId("5551b8f1bb343a620f85f325"),
                "status": "hidden"
            }
        ]
    }{
        "title": "task 1",
        "description": "task 1 desc",
        "order": 10,
        "_id": ObjectId("554a13d4b692088a38f01f3a"),
        "status": "live",
        "subTasks": [
            {
                "title": "task 1 sub 1",
                "content": "aaa",
                "order": -2,
                "_id": ObjectId("554a13d4b692088a38f01f5a"),
                "status": "live"
            },
            {
                "title": "task 1 sub 2",
                "content": "aaa",
                "order": 1,
                "_id": ObjectId("554a13d4b692088a38f01f3a"),
                "status": "live"
            },
            {
                "title": "task 1 sub 3 ",
                "content": "aaa",
                "order": 2,
                "_id": ObjectId("5550d0a61662211332d9a973"),
                "status": "live"
            },
            {
                "title": "task 1 sub 4",
                "content": "aaa",
                "order": 8,
                "_id": ObjectId("554a13d4b692088a38f01f4a"),
                "status": "live"
            }
        ]
    }
]

共有1个答案

潘秦斩
2023-03-14

MongoDB忽略了$展开步骤中的空数组或空数组,因此首先需要用一些值替换空数组或空数组字段,比如说”

要做到这一点,只需在$unWindingsubTask之前添加此管道阶段:

$project: {
             doc: 1, 
             tasks: {
                       title: 1, 
                       description: 1, 
                       order: 1, 
                       status: 1, 
                       subTasks: {
                                    $cond: [
                                              {
                                                 $size: "$tasks.subTasks"
                                              }, 
                                              "$tasks.subTasks", 
                                              ['<e>']
                                           ]
                                 }
                     }
           }

然后,在$组过程中,您需要执行相反的操作,替换您的”

$group: {
           _id: {
                   _id: "$_id._id", 
                   doc: "$_id.doc"}, 
                   tasks: {
                             $push: {
                                       _id: "$_id.task_id", 
                                       title: "$_id.task_doc.title", 
                                       description: "$_id.task_doc.description", 
                                       order: "$_id.task_doc.order", 
                                       status: "$_id.task_doc.status", 
                                       subTasks: {
                                                    $cond: [
                                                              {
                                                                 $eq: ["$subTasks", ["<e>"]]
                                                              }, 
                                                              [], 
                                                              "$subTasks"
                                                           ]
                                                  }
                                     }
                           }
                 }
         }

这是您的最终管道:

[
   {$match: {_id: ObjectId("554a13d4b692088a38f01f3b")}},
   {$project: {tasks: 1, doc: {title: "$title", order: "$order", description: "$description", status: "$status"}}},
   {$unwind: "$tasks"},
   {$project: {doc: 1, tasks: {title: 1, description: 1, order: 1, status: 1, subTasks: {$cond: [{$size: "$tasks.subTasks"}, "$tasks.subTasks", ['<e>']]}}}},
   {$unwind: "$tasks.subTasks"},
   {$sort: {"tasks.order": -1, "tasks.subTasks.order": 1}},
   {$project: {doc: 1, task_id: "$tasks._id", tasks_doc: {title: "$tasks.title", description: "$tasks.description", order: "$tasks.order", status: "$tasks.status"}, subTasks: "$tasks.subTasks"}},
   {$group: {_id: {_id: "$_id", task_id: "$task_id", doc: "$doc", task_doc: "$tasks_doc"}, subTasks: {$push: "$subTasks"}}},
   {$group: {_id: {_id: "$_id._id", doc: "$_id.doc"}, tasks: {$push: {_id: "$_id.task_id", title: "$_id.task_doc.title", description: "$_id.task_doc.description", order: "$_id.task_doc.order", status: "$_id.task_doc.status", subTasks: {$cond: [{$eq: ["$subTasks", ['<e>']]}, [], "$subTasks"]}}}}},
   {$project: {_id: "$_id._id", title: "$_id.doc.title", description: "$_id.doc.description", order: "$_id.doc.order", status: "$_id.doc.status", tasks: 1}}
]

干杯:)

 类似资料:
  • 我在尝试使用MongooseJs在Mongodb中按嵌套数组排序时遇到了一个小问题。 a)一个产品包含任务,每个任务都有子任务。 b)任务有顺序 这是一个示例产品文档: 结果: } 我正在使用MongoDB聚合管道来订购任务 结果: } 预期结果: 我真的很接近了,所有的排序似乎都在工作。我只需要一些帮助来将子任务放回父母体内。非常感谢任何帮助。 谢谢

  • 我在mongodb中的聚合有点问题; 收藏uczelna: 我的合计: 我想找到所有的医生(doktorzy)妇女(名字的最后一个字母a)在一所学校(uczelna)。imie(姓名) 告诉我我做错了什么,谢谢

  • 给定具有以下文档结构的MongoDB集合: 其中每个文档包含一个子文档数组,我希望将集合转换为以下结构的文档: 其中每个子文档现在是主文档中以子文档中的一个值命名的新字段的值(在该示例中,< code>animal字段的值用于创建新字段的名称,即< code>cat和< code>dog)。 我知道如何使用爪哇脚本片段进行。它很慢。我的问题是:如何使用聚合管道完成此操作?

  • 设想一个集合,该集合在聚合的$match操作符上返回具有此结构的文档数组 所以基本上每个返回的文档都共享一个片段(这就是我将如何对它们进行分组),但是每个文档都有一个子文档数组,每个子文档都有不同的_id。 因此,当我使用{slug:“a”}执行$match聚合时,它返回一个数组

  • 我使用Nodejs和MongoDB与expressjs和mongoose库,创建一个具有用户、文章和评论模式的博客API。下面是我使用的模式。

  • 我使用聚合来展开一个数组,并按数组的每个元素分组,以对一些对应的值求和。 我的收藏是: 我想按sourceMedium分组。nodeValue和sum“totalConverions”和“totalConversionValue”,而不使用重复元素。 例如,通过使用展开、分组和和: 对于“nodeValue”:(direct)/(none)“TotalConversions之和等于3,对于“goo