MongoDB $ifNull 空数组仍在添加数据
MongoDB $ifNull empty array still adding data
我有 2 collections,用户和曲目。当我获取用户个人资料时,我想获取他的足迹。
用户 object 将 tracks
作为曲目 ID 数组,第二个 collection 是曲目。
现在我运行下面这段代码:
users
.aggregate([
{
$match: { _id: ObjectId(userId) },
},
{
$lookup: {
from: "tracks",
localField: "tracks",
foreignField: "_id",
as: "tracks",
},
},
{
$unwind: {
path: "$tracks",
preserveNullAndEmptyArrays: true,
},
},
{
$group: {
_id: ObjectId(userId),
username: { $first: "$username" },
profileImg: { $first: "$profileImg" },
socialLinks: { $first: "$socialLinks" },
tracks: {
$push: {
_id: "$tracks._id",
name: "$tracks.name",
categoryId: "$tracks.categoryId",
links: "$tracks.links",
mediaId: isLogged ? "$tracks.mediaId" : null,
thumbnailId: "$tracks.thumbnailId",
views: { $size: { $ifNull: ["$tracks.views", []] } },
downloads: { $size: { $ifNull: ["$tracks.downloads", []] } },
uploadedDate: "$tracks.uploadedDate",
},
},
},
},
])
如果用户没有曲目或没有曲目,$ifNull
语句 returns 和 object 仅包含这些字段,因此看起来像这样:
user: {
// user data
tracks: [{ views: 0, downloads: 0, mediaId: null }]
}
没有找到曲目所以"tracks.views"
无法读取所以我添加了$ifNull语句,如何避免返回空数据?此外,API 调用知道用户是否已登录 (isLogged
),我将 mediaId
设置为 null
。
如果没有找到轨道,为什么代码仍然只添加这 3 个字段?没有轨道可以穿过它们...
编辑:
任何曲目都有 downloads
和 views
包含下载/查看曲目的用户 ID,曲目看起来像
{
"name": "New Track #2227",
"categoryId": "61695d57893f048528d049e5",
"links": {
"youtube": "https://www.youtube.com",
"soundcloud": null,
"spotify": null
},
"_id": "616c90651ab67bbd0b0a1172",
"creatorId": "61695b5986ed44e5c1e1d29d",
"mediaId": "616c90651ab67bbd0b0a1171",
"thumbnailId": "616c90651ab67bbd0b0a1170",
"plays": [],
"status": "pending",
"downloads": [],
"uploadedDate": 1634504805
}
当获取的用户还没有任何曲目 post 时,我收到一个数组,其中一个 object 包含上述字段。
当用户没有曲目时,我期望得到的是一个空数组,正如您在上面看到的响应,曲目 object 未满,仅包含零值的条件键和无效的。
底线我只想要 views
和 downloads
的长度,只有在有一个或更多轨道时,还有 mediaId
我想隐藏它以防用户未登录。如果没有曲目,我不明白为什么 returns 这 3 个字段
用户拥有一首或多首曲目时的预期结果
user: {
// user data
tracks: [
{
name: "New Track #2227",
categoryId: "61695d57893f048528d049e5",
links: {
youtube: "https://www.youtube.com",
soundcloud: null,
spotify: null,
},
_id: "616c90651ab67bbd0b0a1172",
creatorId: "61695b5986ed44e5c1e1d29d",
mediaId: "616c90651ab67bbd0b0a1171",
thumbnailId: "616c90651ab67bbd0b0a1170",
plays: 0,
status: "pending",
downloads: 0,
uploadedDate: 1634504805,
},
];
}
用户没有曲目时的预期结果
user: {
// user data
tracks: [];
}
将此阶段附加到您的管道:
{
$set: {
tracks: {
$filter: {
input: "$tracks",
cond: { $ne: [ { $type: "$$this._id" }, "missing" ] }
}
}
}
}
您还可以将查询修改为如下所示:(查看 live demo here)
此查询通过 $cond
结合 $and
运算符使用条件推送来搜索多个条件。如果 tracks.downloads
或 tracks.plays
不大于 0,我们使用 $$REMOVE
变量(它只是忽略该文档和 returns 一个空数组,就像您正在寻找的那样)。
查询
db.users.aggregate([
{
$match: {
_id: ObjectId("616c80793235ab5cc26dbaff")
},
},
{
$lookup: {
from: "tracks",
localField: "tracks",
foreignField: "_id",
as: "tracks"
}
},
{
$unwind: {
path: "$tracks",
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: ObjectId("616c80793235ab5cc26dbaff"),
username: {
$first: "$username"
},
profileImg: {
$first: "$profileImg"
},
socialLinks: {
$first: "$socialLinks"
},
tracks: {
$push: {
// "IF" plays and downloads > 0
$cond: [
{
$and: [
{
$gt: [
"$tracks.plays",
0
]
},
{
$gt: [
"$tracks.downloads",
0
]
},
]
},
// "THEN" return document
{
_id: "$tracks._id",
name: "$tracks.name",
categoryId: "$tracks.categoryId",
links: "$tracks.links",
mediaId: "$tracks.mediaId",
thumbnailId: "$tracks.thumbnailId",
plays2: {},
plays: "$tracks.plays",
downloads: "$tracks.downloads",
uploadedDate: "$tracks.uploadedDate"
},
// "ELSE" remove
"$$REMOVE"
]
}
}
}
}
])
我有 2 collections,用户和曲目。当我获取用户个人资料时,我想获取他的足迹。
用户 object 将 tracks
作为曲目 ID 数组,第二个 collection 是曲目。
现在我运行下面这段代码:
users
.aggregate([
{
$match: { _id: ObjectId(userId) },
},
{
$lookup: {
from: "tracks",
localField: "tracks",
foreignField: "_id",
as: "tracks",
},
},
{
$unwind: {
path: "$tracks",
preserveNullAndEmptyArrays: true,
},
},
{
$group: {
_id: ObjectId(userId),
username: { $first: "$username" },
profileImg: { $first: "$profileImg" },
socialLinks: { $first: "$socialLinks" },
tracks: {
$push: {
_id: "$tracks._id",
name: "$tracks.name",
categoryId: "$tracks.categoryId",
links: "$tracks.links",
mediaId: isLogged ? "$tracks.mediaId" : null,
thumbnailId: "$tracks.thumbnailId",
views: { $size: { $ifNull: ["$tracks.views", []] } },
downloads: { $size: { $ifNull: ["$tracks.downloads", []] } },
uploadedDate: "$tracks.uploadedDate",
},
},
},
},
])
如果用户没有曲目或没有曲目,$ifNull
语句 returns 和 object 仅包含这些字段,因此看起来像这样:
user: {
// user data
tracks: [{ views: 0, downloads: 0, mediaId: null }]
}
没有找到曲目所以"tracks.views"
无法读取所以我添加了$ifNull语句,如何避免返回空数据?此外,API 调用知道用户是否已登录 (isLogged
),我将 mediaId
设置为 null
。
如果没有找到轨道,为什么代码仍然只添加这 3 个字段?没有轨道可以穿过它们...
编辑:
任何曲目都有 downloads
和 views
包含下载/查看曲目的用户 ID,曲目看起来像
{
"name": "New Track #2227",
"categoryId": "61695d57893f048528d049e5",
"links": {
"youtube": "https://www.youtube.com",
"soundcloud": null,
"spotify": null
},
"_id": "616c90651ab67bbd0b0a1172",
"creatorId": "61695b5986ed44e5c1e1d29d",
"mediaId": "616c90651ab67bbd0b0a1171",
"thumbnailId": "616c90651ab67bbd0b0a1170",
"plays": [],
"status": "pending",
"downloads": [],
"uploadedDate": 1634504805
}
当获取的用户还没有任何曲目 post 时,我收到一个数组,其中一个 object 包含上述字段。
当用户没有曲目时,我期望得到的是一个空数组,正如您在上面看到的响应,曲目 object 未满,仅包含零值的条件键和无效的。
底线我只想要 views
和 downloads
的长度,只有在有一个或更多轨道时,还有 mediaId
我想隐藏它以防用户未登录。如果没有曲目,我不明白为什么 returns 这 3 个字段
用户拥有一首或多首曲目时的预期结果
user: {
// user data
tracks: [
{
name: "New Track #2227",
categoryId: "61695d57893f048528d049e5",
links: {
youtube: "https://www.youtube.com",
soundcloud: null,
spotify: null,
},
_id: "616c90651ab67bbd0b0a1172",
creatorId: "61695b5986ed44e5c1e1d29d",
mediaId: "616c90651ab67bbd0b0a1171",
thumbnailId: "616c90651ab67bbd0b0a1170",
plays: 0,
status: "pending",
downloads: 0,
uploadedDate: 1634504805,
},
];
}
用户没有曲目时的预期结果
user: {
// user data
tracks: [];
}
将此阶段附加到您的管道:
{
$set: {
tracks: {
$filter: {
input: "$tracks",
cond: { $ne: [ { $type: "$$this._id" }, "missing" ] }
}
}
}
}
您还可以将查询修改为如下所示:(查看 live demo here)
此查询通过 $cond
结合 $and
运算符使用条件推送来搜索多个条件。如果 tracks.downloads
或 tracks.plays
不大于 0,我们使用 $$REMOVE
变量(它只是忽略该文档和 returns 一个空数组,就像您正在寻找的那样)。
查询
db.users.aggregate([
{
$match: {
_id: ObjectId("616c80793235ab5cc26dbaff")
},
},
{
$lookup: {
from: "tracks",
localField: "tracks",
foreignField: "_id",
as: "tracks"
}
},
{
$unwind: {
path: "$tracks",
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: ObjectId("616c80793235ab5cc26dbaff"),
username: {
$first: "$username"
},
profileImg: {
$first: "$profileImg"
},
socialLinks: {
$first: "$socialLinks"
},
tracks: {
$push: {
// "IF" plays and downloads > 0
$cond: [
{
$and: [
{
$gt: [
"$tracks.plays",
0
]
},
{
$gt: [
"$tracks.downloads",
0
]
},
]
},
// "THEN" return document
{
_id: "$tracks._id",
name: "$tracks.name",
categoryId: "$tracks.categoryId",
links: "$tracks.links",
mediaId: "$tracks.mediaId",
thumbnailId: "$tracks.thumbnailId",
plays2: {},
plays: "$tracks.plays",
downloads: "$tracks.downloads",
uploadedDate: "$tracks.uploadedDate"
},
// "ELSE" remove
"$$REMOVE"
]
}
}
}
}
])