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

MongoDB单查询实现数组唯一对象添加、排序及切片

MongoDB数组字段去重添加、排序、切片单查询实现

需求与问题

需要通过单查询完成以下操作:

  • 向MongoDB文档的数组字段添加新对象,自动忽略已存在的重复对象
  • 添加完成后按对象的指定字段对数组排序
  • 最后将数组切片至指定长度

此前尝试的方案均存在缺陷:

  • 使用$push配合$sort和$slice能实现排序与切片,但无法避免重复对象
  • 使用$addToSet可以去重,但MongoDB明确提示其不保证元素顺序,无法满足排序需求
  • 尝试聚合管道更新时,不加排序逻辑可正常运行,但添加排序后功能失效

解决方案

利用MongoDB 5.0+支持的聚合管道更新语法,结合$setUnion、$sortArray、$slice三个操作符,可在单查询内完成所有需求:

示例代码(针对students集合)

db.students.updateOne(
  { _id: 5 },
  [
    // 1. 合并现有数组与新元素,自动去重(对象完全匹配则判定为重复)
    {
      $set: {
        quizzes: {
          $setUnion: [
            "$quizzes",
            [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ]
          ]
        }
      }
    },
    // 2. 按指定字段排序(此处按score降序)
    {
      $set: {
        quizzes: {
          $sortArray: {
            input: "$quizzes",
            sortBy: { score: -1 }
          }
        }
      }
    },
    // 3. 切片至指定长度(保留前3个元素)
    {
      $set: {
        quizzes: {
          $slice: ["$quizzes", 3]
        }
      }
    }
  ]
)

通用化代码(适配动态字段与参数)

db.collection(collection).updateOne(
  { _id: updateId },
  [
    // 去重合并新元素与现有数组
    {
      $set: {
        [relatedRel]: {
          $setUnion: [
            `$${relatedRel}`,
            [updatedDoc]
          ]
        }
      }
    },
    // 按自定义规则排序(替换sortBy内的规则即可)
    {
      $set: {
        [relatedRel]: {
          $sortArray: {
            input: `$${relatedRel}`,
            sortBy: { score: -1 } // 示例:按score降序
          }
        }
      }
    },
    // 切片至指定长度
    {
      $set: {
        [relatedRel]: {
          $slice: [`$${relatedRel}`, relatedRelation.limit]
        }
      }
    }
  ]
);

关键操作符说明

  • $setUnion:合并两个数组并自动去重,仅当两个对象的所有键值对完全一致时才会判定为重复
  • $sortArray:MongoDB 5.0+新增的数组排序操作符,可直接对数组按指定字段排序,保证顺序
  • $slice:截取数组至指定长度,支持正向(保留前N个)或反向(保留后N个)截取

特殊场景适配:按指定字段去重(而非整个对象)

如果需要按对象的某个字段(比如wk)判定重复,而非整个对象完全匹配,可调整第一步的逻辑,先过滤掉现有数组中重复字段的元素,再合并新元素:

db.students.updateOne(
  { _id: 5 },
  [
    {
      $set: {
        quizzes: {
          $concatArrays: [
            // 过滤掉现有数组中wk与新元素重复的项
            {
              $filter: {
                input: "$quizzes",
                cond: {
                  $not: {
                    $in: ["$$this.wk", [5, 6, 7]] // 新元素的wk列表
                  }
                }
              }
            },
            [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ]
          ]
        }
      }
    },
    { $set: { quizzes: { $sortArray: { input: "$quizzes", sortBy: { score: -1 } } } } },
    { $set: { quizzes: { $slice: ["$quizzes", 3] } } }
  ]
)

内容的提问来源于stack exchange,提问作者Syd Amir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 03:00:05