MongoDB 如果查找条件失败,则不 return 记录

MongoDB do not return document if condition in lookup fails

我有这个 mongo 数据库查询,它查询一个名为 songs 的集合,对于每首歌曲,returns 相关的相应专辑:

db.songs.aggregate([{
    $lookup: {
            from: "albums",
            let: { album: '$album' },
            as: "album",
            pipeline: [{
                $match: {
                    $expr: {
                        $and: [
                            { $eq: ['$albumId', '$$album._id'] },
                            { $eq: ['$status', 'Draft'] },
                        ]
                    }
                }
            }]
        }
}])

在上面的查询中,我的意图是 return 只有专辑处于 Draft 状态的歌曲,但相反,它 return 是所有歌曲,并且对于专辑不在草稿中的那些,它只是 return 查找中的一个空数组。如果专辑不在 Draft 中,我怎么能完全不 return 歌曲文件?

另外,是否可以将文档中的结果展平?即把专辑的所有字段合并到歌曲文件中?

执行 $lookup 后,您可以过滤掉具有空数组的文档:

{ $match: { album: { $ne: [] } }}

然后是 an example in the MongoDB documentation for the $mergeObjects 运算符,它与您的情况非常相似。假设每首歌属于一张专辑,将您的聚合管道放在一起可能如下所示:

db.songs.aggregate([
{
    $lookup: {
            from: "albums",
            let: { album: '$album' },
            as: "album",
            pipeline: [{
                $match: {
                    $expr: {
                        $and: [
                            { $eq: ['$albumId', '$$album._id'] },
                            { $eq: ['$status', 'Draft'] },
                        ]
                    }
                }
            }]
        }
},
{   $match: { album: { $ne: [] } }},
{
    $replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$album", 0 ] }, "$$ROOT" ] } }
},
{ $project: { album: 0 } }
])

您可能想尝试另一个方向:在 status = Draft 中查找专辑,然后获取歌曲:

db.album.aggregate([
    {$match: {"status":"Draft"}}
    ,{$lookup: {from: "song",
        localField: "album", foreignField: "album",
                as: "songs"}}
    // songs is now an array of docs.  Run $map to turn that into an
    // array of just the song title, and overwrite it (think  x = x + 1):
    ,{$addFields: {songs: {$map: {
                            input: "$songs",
                            in: "$$this.song"
    }} }}
]);

如果 song 文档中有很多 material,您可以使用更高级的 $lookup 来减少查找数组中文档的大小——但是您仍然需要 $map 将其转换为字符串数组。

db.album.aggregate([
    {$match: {"status":"Draft"}}
    ,{$lookup: {from: "song",
                let: { aid: "$album" },
                pipeline: [
                    {$match: {$expr: {$eq:["$album","$$aid"]}}},
                    {$project: {song:true}}
                ],
                as: "songs"}}

    ,{$addFields: {songs: {$map: {
                            input: "$songs",
                            in: "$$this.song"
    }} }}

]);