You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB随机选符合条件文档:累计时长8分钟且含heavy标签

嘿,这个需求确实有点挠头——$sample只能固定取多少条,没法根据累计时长动态调整。不过咱们有两种可行的思路,我给你详细拆解下:

方法一:MongoDB聚合管道实现(适合数据量不大的场景)

如果你用的是MongoDB 4.4及以上版本,可以借助$function来写自定义逻辑,在聚合管道里完成随机选取和时长累加的判断:

  • 先用$match筛选出所有标签为"heavy"的歌曲;
  • 用$group把这些歌曲全部放到一个数组里(注意:如果符合条件的歌曲特别多,这个步骤可能会占用较多内存,所以适合数据量不大的情况);
  • 用$function编写自定义函数,随机打乱数组后逐个累加时长,直到总时长接近但不超过8分钟(也就是480秒,记得统一单位),最后返回选中的歌曲列表。

示例代码大概是这样的:

db.Songs.aggregate([
  { $match: { tags: "heavy" } }, // 筛选标签为heavy的歌曲
  { $group: { _id: null, songs: { $push: "$$ROOT" } } }, // 把所有符合的歌曲放到数组
  {
    $addFields: {
      selectedSongs: {
        $function: {
          body: function(songs) {
            // 先随机打乱数组
            const shuffled = [...songs].sort(() => Math.random() - 0.5);
            let totalDuration = 0;
            const result = [];
            const maxDuration = 8 * 60; // 转换成秒,8分钟=480秒
            for (const song of shuffled) {
              if (totalDuration + song.duration <= maxDuration) {
                result.push(song);
                totalDuration += song.duration;
              } else {
                // 如果当前歌曲加进去超了,就跳过
                continue;
              }
            }
            return result;
          },
          args: ["$songs"],
          lang: "js"
        }
      }
    }
  },
  { $project: { _id: 0, selectedSongs: 1 } } // 只返回选中的歌曲列表
])
方法二:客户端代码处理(更灵活,适合大数据量)

如果符合条件的歌曲数量很多,用聚合管道把所有数据拉到内存里不太现实,那不如把筛选后的歌曲数据拿到客户端,在代码里处理:

  • 先查询所有标签为"heavy"的歌曲,把它们的时长和其他信息一起拿到客户端;
  • 在客户端把歌曲列表随机打乱;
  • 遍历打乱后的列表,逐个累加时长,直到总时长超过8分钟就停止,把之前的歌曲作为结果。

举个JavaScript客户端的例子:

// 先获取所有标签为heavy的歌曲
const heavySongs = await db.collection('Songs').find({ tags: "heavy" }).toArray();
// 随机打乱数组
const shuffledSongs = heavySongs.sort(() => Math.random() - 0.5);
const maxDuration = 8 * 60;
let total = 0;
const selected = [];

for (const song of shuffledSongs) {
  if (total + song.duration <= maxDuration) {
    selected.push(song);
    total += song.duration;
  } else {
    break;
  }
}

console.log('选中的歌曲:', selected);
console.log('总时长:', total);

这个方法的好处是不会给数据库带来太大内存压力,而且你可以根据需求灵活调整逻辑(比如如果最后差一点时长,要不要换一首更短的之类的)。

两种方法各有优劣,你可以根据自己的数据量级和实际需求来选~

内容的提问来源于stack exchange,提问作者Fran b

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:33:06