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"
}} }}
]);
我有这个 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"
}} }}
]);