Spring Boot嵌入式MongoDB:Java创建函数、调用及批量数据导入问题
解决方案
一、批量插入文档优化
不用逐个插入,直接用MongoTemplate.insertAll()批量处理文档集合即可:
// 示例:批量插入自定义实体类文档 List<YourEntity> entityList = Arrays.asList(new YourEntity("val1"), new YourEntity("val2")); mongoTemplate.insertAll(entityList);
如果是JSON格式的批量数据,转成Document集合后用insertMany效率更高:
// 从JSON数组转成Document列表 String jsonBatch = "[{\"name\":\"test1\"}, {\"name\":\"test2\"}]"; List<Document> docList = Arrays.asList(new ObjectMapper().readValue(jsonBatch, Document[].class)); mongoTemplate.getCollection("target-collection").insertMany(docList);
二、在system.js中创建序列函数
system.js就是MongoDB存储服务器端JS函数的普通集合,直接往里面插入函数文档即可,两种实现方式:
方式1:直接操作system.js集合(推荐)
// 把函数代码写成字符串 String funcCode = "function getNextSequence(seqName) { " + "var seqDoc = db.dbSequence.findAndModify({ " + "query: {seq: seqName}, " + "update: {$inc: {value: 1}}, " + "new: true " + "}); " + "return seqDoc.value; " + "}"; // 构造要插入的文档,_id对应函数名 Document funcDoc = new Document("_id", "getNextSequence") .append("value", funcCode); // 用replaceOne+upsert,不存在就插入,存在就更新 mongoTemplate.getCollection("system.js").replaceOne( Filters.eq("_id", "getNextSequence"), funcDoc, new ReplaceOptions().upsert(true) );
方式2:执行MongoDB命令(注意:eval在4.2+版本已弃用)
MongoDatabase db = mongoTemplate.getMongoDbFactory().getMongoDatabase(); Document command = new Document("eval", "db.system.js.save({_id: 'getNextSequence', value: function getNextSequence(seqName) { " + "var seqDoc = db.dbSequence.findAndModify({query: {seq: seqName}, update: {$inc: {value: 1}}, new: true}); " + "return seqDoc.value; " + "}})" ); db.runCommand(command);
三、调用序列函数的方法
方式1:用eval调用(不推荐,已弃用)
MongoDatabase db = mongoTemplate.getMongoDbFactory().getMongoDatabase(); Document cmd = new Document("eval", "getNextSequence('user-id-seq')"); Document result = db.runCommand(cmd); Long nextSeq = result.getLong("retval");
方式2:直接在Java里实现逻辑(推荐,无版本依赖)
没必要依赖服务器端函数,直接在Java里写findAndModify逻辑更稳妥:
// 查询条件:匹配序列名称 Query query = Query.query(Criteria.where("seq").is("user-id-seq")); // 更新操作:value自增1 Update update = new Update().inc("value", 1); // 配置:返回更新后的新文档 FindAndModifyOptions options = FindAndModifyOptions.options().returnNew(true); // 执行操作,返回更新后的序列文档 DbSequence seqDoc = mongoTemplate.findAndModify(query, update, options, DbSequence.class); Long nextSeq = seqDoc.getValue();
对应的DbSequence实体类:
@Document(collection = "dbSequence") public class DbSequence { @Id private String id; private String seq; private Long value; // 构造器、getter、setter public DbSequence(String seq, Long value) { this.seq = seq; this.value = value; } }
方式3:聚合中调用(MongoDB 4.4+支持)
如果要在聚合管道里使用这个函数,用$function操作符:
Aggregation agg = Aggregation.newAggregation( Aggregation.project() .and(Aggregation.function( "getNextSequence", Arrays.asList("user-id-seq"), Long.class )).as("nextSequence") ); AggregationResults<Document> results = mongoTemplate.aggregate(agg, "your-collection", Document.class); Long nextSeq = results.getMappedResults().get(0).getLong("nextSequence");
四、初始化时机
把这些初始化逻辑放在测试类的@BeforeAll或者@BeforeEach方法中,确保测试开始前完成所有准备:
@SpringBootTest class YourTestClass { @Autowired private MongoTemplate mongoTemplate; @BeforeAll static void initTestData(@Autowired MongoTemplate mongoTemplate) { // 初始化dbSequence的初始值(比如用户序列从0开始) mongoTemplate.insert(new DbSequence("user-id-seq", 0L), "dbSequence"); // 批量插入测试文档 // 创建system.js函数 } }
内容的提问来源于stack exchange,提问作者pagurix
相关产品推荐
相关产品推荐

