使用$ addFields时如何将值合并到单个数组中?

时间:2019-06-10 16:12:05

标签: mongodb mongoose

我是MongoDB的新手,并且基本上是RDBMS的新手。我正在使用$ addFields从联接表中检索单个列,如下所示,

Movies集合结构:

{
    "_id" : ObjectId("5cd30088ccbfc800173dcd42"),
    "name" : "NGK",
    "sourceId" : "5cd3007cccbfc800173dcd41"
}

Events集合结构:

{
    "_id" : ObjectId("5cfa8b20ee38ea10717b3e72"),
    "movieId" : ObjectId("5cd720dda185d600170278fd"),
    "type" : "news",
    "description" : "Kathua rape, murder case verdict LIVE updates: Victim's family likely to challenge verdict giving life term to three main accused",
    "resources" :{
        "posterLinks" : [ 
            {
                "_v" : 1560167750,
                "image" : "xxxx/posters/orgomohvopr0ykxgmq2g"
            }, 
            {
                "_v" : 1560167752,
                "image" : "xxxx/posters/bnskv36qbdj9wnaomvre"
            }
        ],
        "youtubeLinks" : [ 
            "https://www.youtube.com/watch?v=ocnzgwjXdLw", 
            "https://www.youtube.com/watch?v=oLRHNYQ-Dno"
        ]
    },
    "createdDate" : ISODate("2019-06-07T16:04:48.980Z")
}, 
{
    "_id" : ObjectId("5cfa8d03e8604410c74a65ab"),
    "movieId" : ObjectId("5cd720dda185d600170278fd"),
    "sourceId" : ObjectId("5cfa0bb8f5b21607b245eff3"),
    "type" : "news",
    "description" : "Former Pakistani president Asif Ali Zardari arrested on corruption charges",
    "resources" : {
        "posterLinks" : [ 
            {
                "_v" : 1560167915,
                "image" : "xxxx/posters/ldu3iceqarnaaw1qeyhk"
            }, 
            {
                "_v" : 1560167917,
                "image" : "xxxx/posters/r1oi172lpxdylnqaify5"
            }
        ]
    },
    "createdDate" : ISODate("2019-06-07T16:12:51.927Z")
}

我的查询

db.getCollection('movies').aggregate([
   {
        $lookup: {
            from: "events",
            localField: "_id",
            foreignField: "movieId",
            as: "events"
        }
   },
   { 
       $addFields: { 
           "resources": "$events.resources"
        }
   }
]);

结果如下,

{
    "_id" : ObjectId("5cd720dda185d600170278fd"),
    "action" : [ 
        "5cf35c027807f0f65b5e9627"
    ],
    "events" : [ 
        {
            "_id" : ObjectId("5cfa8b20ee38ea10717b3e72"),
            "movieId" : ObjectId("5cd720dda185d600170278fd"),
            "sourceId" : ObjectId("5cfa0bb8f5b21607b245eff3"),
            "type" : "news",
            "description" : "Kathua rape, murder case verdict LIVE updates: Victim's family likely to challenge verdict giving life term to three main accused",
            "resources" :{
                "posterLinks" : [ 
                    {
                        "_v" : 1560167750,
                        "image" : "xxxx/posters/orgomohvopr0ykxgmq2g"
                    }, 
                    {
                        "_v" : 1560167752,
                        "image" : "xxxx/posters/bnskv36qbdj9wnaomvre"
                    }
                ],
                "youtubeLinks" : [ 
                    "https://www.youtube.com/watch?v=ocnzgwjXdLw", 
                    "https://www.youtube.com/watch?v=oLRHNYQ-Dno"
                ]
            },
            "createdDate" : ISODate("2019-06-07T16:04:48.980Z")
        }, 
        {
            "_id" : ObjectId("5cfa8d03e8604410c74a65ab"),
            "movieId" : ObjectId("5cd720dda185d600170278fd"),
            "sourceId" : ObjectId("5cfa0bb8f5b21607b245eff3"),
            "type" : "news",
            "description" : "Former Pakistani president Asif Ali Zardari arrested on corruption charges",
            "resources" : {
                "posterLinks" : [ 
                    {
                        "_v" : 1560167915,
                        "image" : "xxxx/posters/ldu3iceqarnaaw1qeyhk"
                    }, 
                    {
                        "_v" : 1560167917,
                        "image" : "xxxx/posters/r1oi172lpxdylnqaify5"
                    }
                ]
            },
            "createdDate" : ISODate("2019-06-07T16:12:51.927Z")
        }, 
    "resources" : [ 
        {
            "posterLinks" : [ 
                {
                    "_v" : 1560167750,
                    "image" : "xxxx/posters/orgomohvopr0ykxgmq2g"
                }, 
                {
                    "_v" : 1560167752,
                    "image" : "xxxx/posters/bnskv36qbdj9wnaomvre"
                }
            ],
            "youtubeLinks" : [ 
                "https://www.youtube.com/watch?v=ocnzgwjXdLw", 
                "https://www.youtube.com/watch?v=oLRHNYQ-Dno"
            ]
        }, 
        {
            "posterLinks" : [ 
                {
                    "_v" : 1560167915,
                    "image" : "xxxx/posters/ldu3iceqarnaaw1qeyhk"
                }, 
                {
                    "_v" : 1560167917,
                    "image" : "xxxx/posters/r1oi172lpxdylnqaify5"
                }
            ]
        }
    ]
}

我得到了预期的结果,但是正如您所看到的,当一部电影的事件多于一个事件时,当一部电影的事件多于一个时,资源中会有多个数组。

我正在寻找一种为具有单个posterLinksyoutubeLinks对象的每部电影获取单个资源数组的方法,我知道可以通过在值被设置后使用循环来实现检索。但是查询本身有办法做到吗?

我也不需要结果中的事件数组,因为所需的资源已经在结果中可用。任何建议,将不胜感激。

1 个答案:

答案 0 :(得分:1)

对于任意资源,您可以使用sub-query syntax of lookup

类似这样的东西:

db.getCollection('movies').aggregate([
    {
       $lookup:
         {
            from: "events",
            let: { movieId: "$_id" },
            pipeline: [ 
                { $match: { $expr: { $eq: ["$movieId", "$$movieId"] } } },
                { $project: { resources: { $objectToArray: "$resources" } } },
                { $unwind: "$resources" },
                { $unwind: "$resources.v" },
                { $group: { _id:"$resources.k", "v": { $addToSet:"$resources.v" } } },
                { $group: { _id:null, resources: { $push: { k:"$_id", v:"$v" } } } },
                { $project: { resources: { $arrayToObject: "$resources" } } },
                { $replaceRoot: { newRoot:"$resources" } }
            ],
            as: "events"
         }
    },
    { $project: { resources:0 } },
    { $unwind: "$events" }
]);

查找中的管道按键对资源进行分组。 它允许在结果数组中重复资源。如果不打算对子查询管道进行相应的修改。

请记住,这是一个非常昂贵的查询。如果资源结构是预定义的且稳定的,则可以通过在主管道中使用带有硬编码键的数组函数来提高查询效率。