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

如何在MongoDB两个集合间实现文档反向引用及数据迁移?

MongoDB 反向引用迁移需求

我有一个person集合,文档结构如下:

_id: ObjectId('64103dd44c7b1355e4812e87'),
sport: 'Football',
name: 'Brian',
teams: [
    ObjectId('62f63b38e6a6cbb9a58c58c4'),
    ObjectId('64219e4eb5924e070a23f846')
]

_id: ObjectId('642ad97d0c945ff64f2a5f4c'),
sport: 'Football',
name: 'Marc',
teams: [
    ObjectId('64219e4eb5924e070a23f846')
]

_id: ObjectId('64269d6c38364df7ca902d75'),
sport: 'Basketball',
name: 'Francis',
teams: [
    ObjectId('641453c9adc10762db6997cb'),
    ObjectId('64269ebc38364df7ca902e17')
]

另外还有一个teams集合,文档结构如下:

_id: ObjectId('62f63b38e6a6cbb9a58c58c4'),
sport: 'Football',
name: 'Team A',
persons: [
    ObjectId('642ada46f785be5eb0042f63')
]

_id: ObjectId('64219e4eb5924e070a23f846'),
sport: 'Football',
name: 'Team B',
persons: [
]

_id: ObjectId('62f3a57bcc852536a665b179'),
sport: 'Football',
name: 'Team C',
persons: [
]

_id: ObjectId('641453c9adc10762db6997cb'),
sport: 'Basketball',
name: 'Team D',
persons: [
    ObjectId('642ada848b8c7b48102c3cb4')
]

_id: ObjectId('64269ebc38364df7ca902e17'),
sport: 'Basketball',
name: 'Team E',
persons: [
    ObjectId('642ada95f8f190e02582e10d')
]

需求说明

  • 将person的ID存入对应teams文档的persons数组中,保留teams原有的persons引用
  • 迁移需匹配相同运动类型(如足球项目的人员只能迁移到足球队伍)
  • 最后移除person文档中的teams字段

预期结果

person集合

_id: ObjectId('64103dd44c7b1355e4812e87'),
sport: 'Football',
name: 'Brian'

_id: ObjectId('642ad97d0c945ff64f2a5f4c'),
sport: 'Football',
name: 'Marc'

_id: ObjectId('64269d6c38364df7ca902d75'),
sport: 'Basketball',
name: 'Francis'

teams集合

_id: ObjectId('62f63b38e6a6cbb9a58c58c4'),
sport: 'Football',
name: 'Team A',
persons: [
    ObjectId('62f641ae84f995495a0f567f')
]

_id: ObjectId('64219e4eb5924e070a23f846'),
sport: 'Football',
name: 'Team B',
persons: [
    ObjectId('642ada46f785be5eb0042f63'),
    ObjectId('64103dd44c7b1355e4812e87'),
    ObjectId('642ad97d0c945ff64f2a5f4c')
]

_id: ObjectId('62f3a57bcc852536a665b179'),
sport: 'Football',
name: 'Team C',
persons: [
]

_id: ObjectId('641453c9adc10762db6997cb'),
sport: 'Basketball',
name: 'Team D',
persons: [
    ObjectId('642ada848b8c7b48102c3cb4'),
    ObjectId('64269d6c38364df7ca902d75')
]

_id: ObjectId('64269ebc38364df7ca902e17'),
sport: 'Basketball',
name: 'Team E',
persons: [
    ObjectId('642ada95f8f190e02582e10d'),
    ObjectId('64269d6c38364df7ca902d75')
]

实现方案

可以在Mongo Shell中执行以下脚本完成迁移:

db.person.find().forEach(function(person) {
    // 遍历当前用户关联的所有队伍ID
    person.teams.forEach(function(teamId) {
        // 仅更新同运动类型的队伍,避免跨项目迁移
        db.teams.updateOne(
            { _id: teamId, sport: person.sport },
            { $addToSet: { persons: person._id } } // 用$addToSet避免重复添加同一用户ID
        );
    });
    // 移除当前用户文档中的teams字段
    db.person.updateOne(
        { _id: person._id },
        { $unset: { teams: "" } }
    );
});

关键说明

  • $addToSet确保同一个用户ID不会被重复添加到队伍的persons数组中,符合数据唯一性要求
  • 过滤条件{ _id: teamId, sport: person.sport }严格限制了同项目迁移,满足运动类型匹配规则
  • $unset指令用于彻底移除person文档中的teams字段

注意事项

  1. 执行前务必备份数据库,防止数据异常
  2. 若数据量较大,建议分批处理,避免单次遍历过多文档引发性能问题
  3. 先在测试环境验证脚本效果,确认无误后再在生产环境执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:47:04