【问题标题】:MongoDB $ifNull empty array still adding dataMongoDB $ifNull 空数组仍在添加数据
【发布时间】:2021-12-05 00:52:50
【问题描述】:

我有 2 个集合,用户和曲目。当我获取用户个人资料时,我想获取他的曲目。 用户对象有 tracks 作为轨道 ID 的数组,第二个集合是轨道。

现在我在下面运行这段代码:

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 语句会返回一个仅包含这些字段的对象,因此它看起来像这样:

user: {
    // user data
    tracks: [{ views: 0, downloads: 0, mediaId: null }]
}

没有找到轨道所以无法读取"tracks.views" 所以我添加了 $ifNull 语句,如何避免它返回空数据?此外,API 调用知道用户是否登录(isLogged),我将mediaId 设置为null。 如果没有找到轨道,为什么代码仍然只添加这 3 个字段?没有轨道可以通过它们...

编辑: 任何轨道都有 downloadsviews 包含下载/查看轨道的用户 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
}

当获取的用户还没有任何跟踪帖子时,我会收到一个数组,其中包含一个包含上述字段的对象。

当用户没有轨道时,我期望得到的是一个空数组,正如您在上面的响应中看到的那样,轨道对象未满并且仅包含具有零值和空值的条件键。 底线我想要viewsdownloads 的长度,只有当有一个或更多的轨道时,还有mediaId,我想隐藏它以防用户没有登录。如果没有曲目,我不明白为什么它会返回这 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: [];
}

【问题讨论】:

  • 想要的输出是什么,你能添加一个示例吗?如果缺少空数据字段?检查$$REMOVE也许它可以帮助你
  • @Takis_ 你好!如果用户没有发布曲目,我希望得到一个用于下载/查看的空数组,现在它发送这 3 个字段。它应该是整个轨道(如果找到的话)或者什么都没有......
  • 不清楚你想得到什么,也许试试views: { $ifNull: ["$tracks.views", []] } views: { $ifNull: ["$tracks.views", "$$REMOVE"] }
  • @WernfriedDomscheit 更新了问题,尝试使用 "$$REMOVE" 而不是 [] 并抛出此错误 The argument to $size must be an array, but was of type: missing
  • 提供一些示例输入数据是一个很好的起点。还请提供预期的样本输出数据。

标签: node.js mongodb mongodb-query aggregate aggregation


【解决方案1】:

将此阶段附加到您的管道:

{
  $set: {
    tracks: {
      $filter: {
        input: "$tracks",
        cond: { $ne: [ { $type: "$$this._id" }, "missing" ] } 
      }
    }
  }
}

【讨论】:

  • 你找到我了!谢谢,这正是我需要的。
【解决方案2】:

您还可以将查询修改为如下所示:(查看live demo here

此查询使用通过$cond 加上$and 运算符的条件推送来搜索多个条件。如果tracks.downloadstracks.plays 不大于0,我们使用$$REMOVE 变量(它只是忽略该文档并返回一个空数组,就像您正在寻找的那样)。

查询

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"
          ]
        }
      }
    }
  }
])

【讨论】:

  • 我可以看到播放和下载有$and的条件> 0,如果该用户的曲目有0次下载/播放怎么办?还是下载次数超过 1 次且观看次数为 0 次的曲目(反之亦然)?
  • 我将条件更改为$ifNull: ["$tracks._id", false],它只有在有ID时才有效:),所以无论播放/下载是0还是其他只要轨道存在@987654323就可以了@
猜你喜欢
  • 1970-01-01
  • 2013-09-14
  • 2023-03-13
  • 2021-12-09
  • 2021-11-21
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多