如何在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字段
注意事项
- 执行前务必备份数据库,防止数据异常
- 若数据量较大,建议分批处理,避免单次遍历过多文档引发性能问题
- 先在测试环境验证脚本效果,确认无误后再在生产环境执行
内容的提问来源于stack exchange,提问作者TheStranger
相关产品推荐
相关产品推荐

