基于group by和sort操作删除多个文档

Delete multiple documents based on group by and sort operation

我是新来的 MongoDB 我需要你的帮助。我想根据特定条件从集合中删除多个文档,即根据 empID 分组并删除除该 empID 的最新记录之外的记录。

假设我的数据集如下所示:

[
  {
    _id: 1,
    employeeId: "50052196",
    name: "abc",
    lastUpdatedOn: ISODate("2022-01-10T10:25:38.859+00:00")
  },
  {
    _id: 2,
    employeeId: "50052197",
    name: "xyz",
    lastUpdatedOn: ISODate("2022-01-17T10:25:38.859+00:00")
  },
  {
    _id: 3,
    employeeId: "50052198",
    name: "pqr",
    lastUpdatedOn: ISODate("2022-01-17T10:25:38.859+00:00")
  },
  {
    _id: 4,
    employeeId: "50052196",
    name: "abc",
    lastUpdatedOn: ISODate("2022-01-12T11:30:58.435+00:00")
  },
  {
    _id: 5,
    employeeId: "50052196",
    name: "abc",
    lastUpdatedOn: ISODate("2022-01-15T15:45:00.159+00:00")
  }
]

在上面的数据集中,employeeID : 50052196 是与字段 lastUpdatedOn 一起定期插入的重复文档。因为 lastUpdatedOn 只不过是 record/document 创建日期。

现在,我想保留具有最新 lastUpdatedOn 值的文档,即 lastUpdatedOn:2022-01-15T15:45:00.159+00:00 对应 employeeID : 50052196

我已经阅读了 MongoDB 文档,我发现我们无法编写删除查询以及分组依据和排序操作或者如果我们选择聚合管道,那么我们无法删除聚合内的文档. 我正在检查 Bulk.find.remove() 的选项,但我还是无法弄清楚如何对 employeeId 进行分组。

我想到的另一种方法是,根据某些条件,我将添加一个字段,即 isActive: true。使用正常的 deleteMany() 操作我可以删除 isActive: false 文件。但根据政策,我不能修改文件。 集合中的插入操作由第三方应用处理,我们无法修改。

由于文档数量较多,我想编写一个代码,既能减少时间和资源消耗,又能遵循最佳实践。非常感谢您的帮助。任何人都可以建议我解决这种情况的好选择。非常感谢您的帮助。

注意:我必须为多个 MongoDB 集合编写相同类型的删除代码。这是我正在考虑编写的一种清理脚本。

您可以使用任何您想要的管道并在末尾添加一个 $out 阶段,这将覆盖所选的集合。

例如:

db.collection.aggregate([
  {
    $sort: {
      lastUpdatedOn: -1
    }
  },
  {
    $group: {
      _id: "$employeeId",
      root: {
        $first: "$$ROOT"
      }
    }
  },
  {
    $replaceRoot: {
      newRoot: "$root"
    }
  },
  {
    $out: "collection"
  }
])

Mongo Playground

一种更可控的代码方式,逐个用户迭代:

const userIds = await db.collection.distinct('employeeId');
for (let i = 0; i < userIds.length; i++) {
    const userId = userIds[i];
    const employeeRecords = await db.collection.find({ 'employeeId': userId }).sort({ lastUpdatedOn: -1 }).toArray();
    employeeRecords.pop();
    await db.collection.deleteMany({ _id: { $in: employeeRecords.map(v => v._id) } });
}

(这应该 运行 并行。为清楚起见,它写在 for 循环中)