MongoDB的常见数据更正需求总结
MongoDB的常见数据更正需求总结

MongoDB的常见数据更正需求总结

引言

日常工作中,经常会遇到程序bug或者别的情况需要找DBA更改数据库数据修复的场景,因此需要平时就总结好怎么更新数据,甚至脚本命令可以提前准备,紧急时刻直接使用即可,这样就免得一时手足无措,手忙脚乱。

一、更新数据需求

  1. 如果是更新少量(5个以下)记录数据,推荐使用GUI图形化工具来更新
  2. 如果是要批量更新大量数据,就只能使用批量更新方式。

1. 更新数据需求(简单)

字段数据整体更新,使用set操作符

db.t1.find().forEach( 
        function(myDoc) { 
            print(" user_id: " + myDoc.user_id +  " OrderNum: " + myDoc.OrderNum); 
            db.Orders.updateMany({user_id: myDoc.user_id}, {$set: {OrderNum: myDoc.OrderNum}} );
        } 
);
#通常Orders集合上user_id上创建有索引。

字段数据累加,使用inc操作符

db.t1.find().forEach( 
        function(myDoc) { 
           db.Account.updateMany({user_id: myDoc.user_id}, {$inc: {OrderNum: 5}} );
        } 
);

字段数据相乘,使用inc操作符

db.t1.find().forEach( 
        function(myDoc) { 
            db.Account.updateMany({user_id: myDoc.user_id}, {$mul: {OrderNum: 10}} );
        } 
);

2. 批量更新字段的数据(复杂)

原始数据如下

[direct: mongos] test> db.t3.find({gid:300023700}, {rechargeModuleData:1})
[
  {
    _id: ObjectId("0881d8dd000000000000002e"),
    rechargeModuleData: {
      totalRecharge: 0,
      totalRechargeDol: 0,
      records: {
        '3001': 0,
        '3002': 0,
        '3003': 0
      },
      monthCard: 0,
      fishMonthCard: 0,
      bigMonthCard: 0,
      doubleResetVersion: 1,
      buytimes: {}
    }
  }
]

2.1 需求一:将rechargeModuleData.totalRecharge 里面的值改成 特定数值

方法1:直接更新
db.t3.updateOne({gid:300023700}, {$set: {"rechargeModuleData.totalRecharge": 4}} )
方法2:从临时集合里面更新,方便为不同的GID更新成不同的值。
-- 查看t1原始数据
[direct: mongos] test> db.t1.find()
[
  {
    _id: ObjectId("643e64087084a56fee3a663d"),
    user_id: 300023700,
    totalRecharge: 15
  },
  {
    _id: ObjectId("643e640e7084a56fee3a663e"),
    user_id: 2,
    totalRecharge: 1
  }
]

-- 批量更新
db.t1.find().forEach( 
        function(myDoc) { 
            db.t3.updateMany(
                    {gid: myDoc.user_id}, 
                    {$set: {"rechargeModuleData.totalRecharge": myDoc.totalRecharge}}
             );
        } 
);

2.2 需求二:rechargeModuleData.records 往里面增加条目

--- 查看临时表数据
[direct: mongos] test> db.t1.find()
[
  {
    _id: ObjectId("643e64087084a56fee3a663d"),
    user_id: 300023700,
    r:  { '1': 1111 }
  },
  { _id: ObjectId("643e640e7084a56fee3a663e"), user_id: 2 }
]


-- 其中equip表如下, 期望是往USER_ID=300023700的数据里面加一条
 {
    _id: ObjectId("0881d8dd000000000000002e"),
    user_id: 300023700,
    rechargeModuleData: {
      totalRecharge: 0,
      totalRechargeDol: 0,
      records: {
        '3001': 0,
        '3002': 0,
        '3003': 0,
        '1': 1111
      },
      monthCard: 0,
      fishMonthCard: 0,
      bigMonthCard: 0,
      doubleResetVersion: 1,
      buytimes: {}
    }
  }

更新方法:遍历临时表


db.t1.find().forEach( 
        function(myDoc) { 
            print(myDoc.user_id, myDoc.r)
            db.equip.updateOne(
                    {user_id: myDoc.user_id}, 
                   {$set: {"rechargeModuleData.records": myDoc.r}}
            );
        } 
);

3. 批量更新数据(数组追加)

原始数据如下

[direct: mongos] test> db.t3.find({gid:300023700}, {"activityModuleData.activityRolling":1})
[
  {
    _id: ObjectId("0881d8dd000000000000002e"),
    activityModuleData: {
      activityRolling: {
        rewards: [
          { _id: 10400000, count: 999, isDouble: 0 },
          { _id: 10800000, count: 5, isDouble: 0 },
          { _id: 12300000, count: 20, isDouble: 0 },
          { _id: 10400000, count: 200, isDouble: 0 },
          { _id: 10400000, count: 99, isDouble: 0 },
          { _id: 30300001, count: 20, isDouble: 1 },
          { _id: 10800000, count: 1, isDouble: 1 },
          { _id: 12300000, count: 5, isDouble: 0 },
          { _id: 30300001, count: 10, isDouble: 1 }
        ],
        records: []
      }
    }
  }
]

3.1 需求一:往activityModuleData.activityRolling.rewards数组里面追加数据

方法一:常规更新
db.t3.updateOne(
        {gid:300023700},
        {$push: 
             {"activityModuleData.activityRolling.rewards":  { _id:11,count:11, isDouble:11}   } 
        }
)

最终效果如下:

方法二: 批量更新
-- 原始数据:
[direct: mongos] test>  db.t1.find()
[
  {
    _id: ObjectId("643e64087084a56fee3a663d"),
    user_id: 300023700,
     r: { _id: 111, count: 111, isDouble: 111 }
  },
  { _id: ObjectId("643e640e7084a56fee3a663e"), user_id: 2 }
]


-- 批量更新, 批量将r里面内容追加到数组中
db.t1.find().forEach( 
        function(myDoc) { 
            db.t3.updateMany(
                    {gid: myDoc.user_id}, 
                    {$push: {"activityModuleData.activityRolling.rewards": myDoc.r}}
             );
        }
);

最终效果:

二、拷贝数据需求

处理集合拷贝到另一个数据库

方法1(物理方式):使用自带的rename命令,但是限制比较多。

  1. 如果目标数据库不存在, 目前MongoDB不提供显示创建数据库的命令,只有隐士创建数据库。

报错提示:”database ycf_testa not found”

  1. 源库和目标库必须在同一个shard。

报错提示:”Source and destination collections must be on same shard”

  1. 该方法也可以用来重命集合名,但是该集合不能是分片集合。

报错提示:”MongoServerError: You can’t rename a sharded collection”


> use admin
switched to db admin

> db.runCommand(
      {
          renameCollection: 'gcgame.Account',
          to              : 'ycf_test.Account'
      }
  );

方法2 (逻辑方式):循环拷贝插入

同一个数据库(test)

use test
db.user_info.find().forEach(
     function(x)        {
        db.ycf_user_info_bak.insert(x);
     }
)

把test01.t1 拷贝到test02.t2_ycf_bak, 也可以在find里面限制拷贝条件

use test01
db.t1.find().forEach(
     function(d){
        db.getSiblingDB('test02')['t2_ycf_bak'].insert(d);
     }
)

总结

平时多测试练习,孰能生巧,当遇到紧急情况下才能做到胸有成竹,不急不躁,从容处理。