引言
日常工作中,经常会遇到程序bug或者别的情况需要找DBA更改数据库数据修复的场景,因此需要平时就总结好怎么更新数据,甚至脚本命令可以提前准备,紧急时刻直接使用即可,这样就免得一时手足无措,手忙脚乱。
一、更新数据需求
- 如果是更新少量(5个以下)记录数据,推荐使用GUI图形化工具来更新
- 如果是要批量更新大量数据,就只能使用批量更新方式。
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命令,但是限制比较多。
- 如果目标数据库不存在, 目前MongoDB不提供显示创建数据库的命令,只有隐士创建数据库。
报错提示:”database ycf_testa not found”
- 源库和目标库必须在同一个shard。
报错提示:”Source and destination collections must be on same shard”
- 该方法也可以用来重命集合名,但是该集合不能是分片集合。
报错提示:”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);
}
)
总结
平时多测试练习,孰能生巧,当遇到紧急情况下才能做到胸有成竹,不急不躁,从容处理。