最近有一个需求,需要从一个MongoDB操作日志表中取出所有对mongo集合的处理,然后执行操作。简单来说就是找到之前所有用户的操作,然后在一张空白集合中再次演绎一遍。因为这些操作基本都不相同即每次修改都是不一样的,所以从效率上考虑采用批量更新的方法。
参考文章:https://www.jianshu.com/p/3577ccb722a1
原文对批量更新的讲述比较细。由于讲述的是mongo2.0.0之前版本,而我使用的是2.1.5,故而实施过程中会出现了一些版本兼容问题:
mongoTemplate.getCollection()返回的类型由之前的 DBCollection 变成了 MongoCollection
下面给出修改后的核心代码(如有兴趣可参考尹吉欢文章 https://www.jianshu.com/p/3577ccb722a1 )。
1. 定义一个[封装更新与查询]工具类
public class BatchUpdateOptions {
private Query query;
private Update update;
private boolean upsert = false;
private boolean multi = false;
}
2. 封装一个Mongo数据访问基础对象
public class MongoBaseDao {
/**
* 批量更新
* @param ordered 如果为true,一条语句更新失败,剩下的语句将不再执。如果为false,一条语句更新失败,剩下的将继续执行。默认为true。
* @return
*/
public static int batchUpdate(MongoTemplate mongoTemplate, String collectionName, List<BatchUpdateOptions> options, boolean ordered) {
return doBatchUpdate(mongoTemplate, collectionName, options, ordered);
}
private static int doBatchUpdate(MongoTemplate mongoTemplate, String collName, List<BatchUpdateOptions> options, boolean ordered) {
DBObject command = new BasicDBObject();
command.put("update", collName);
List<BasicDBObject> updateList = new ArrayList<BasicDBObject>();
for (BatchUpdateOptions option : options) {
BasicDBObject update = new BasicDBObject();
update.put("q", option.getQuery().getQueryObject());
update.put("u", option.getUpdate().getUpdateObject());
update.put("upsert", option.isUpsert());
update.put("multi", option.isMulti());
updateList.add(update);
}
command.put("updates", updateList);
command.put("ordered", ordered);
Document document = mongoTemplate.getDb().runCommand((Bson) command);
System.out.println("doc:"+document);
System.out.println("doc--n:"+document.get("n"));
System.out.println("doc--nModified:"+document.get("nModified"));
// n为符合Query查询的记录总数 因为是根据id进行的查询, 原则上只要符合查询的记录数等于要更新的数量就代表成功
Object n = document.get("n");
System.out.println("doc--n--class:"+n.getClass());
if(n.getClass()==Integer.class){
return (Integer)n;
}
return Integer.parseInt(String.valueOf(n));
}
}
注意: 这里对原作者的代码进行了修改【联系到了原作者,原作者给出的方法】:
- 将DBObjec类型的command转换为了Bson。
- 执行命令的函数改为了mongoTemplate.getDb().runCommand()
mongo官方手册给出的更新命令的说明:
https://docs.mongodb.com/manual/reference/command/update/
3. 调用实例
List<BatchUpdateOptions> list = new ArrayList<BatchUpdateOptions>();
// 注意upsert置为false, 更新过程不做插入
for (Map map : aus) {
Update update = new Update();
for (Object k : map.keySet()
) {
update.set(String.valueOf(k), map.get(k));
}
Query query = Query.query(Criteria.where(primaryKey).is(map.get("id")));
BatchUpdateOptions options = new BatchUpdateOptions(query, update, false, true);
list.add(options);
}
int n = MongoBaseDao.batchUpdate(mongoTemplate, collectionName, list, true);
boolean res = (n == aus.size());
aus为封装的所有对mongo进行更新的集合。