最近我们的业务需求有增量更新,虽然后来考虑到复杂性,放弃了对嵌套文档的深嵌套更新,改为删除第一层嵌套再重新入。但嵌套更新的方法还是值得记录下来的。
mongobd 集合的数据格式为
{
"_id" : "123",
"personCerts" : [
{
"perId" : "111",
"perName" : "嘿嘿嘿",
"certifications" : [
{
"certNo" : "02333629",
"regType" : "072",
"regMajor" : "010"
}
]
},
{
"perId" : "222",
"perName" : "哈哈哈",
"certifications" : [
{
"certNo" : "02333629",
"regType" : "071",
"regMajor" : "020"
}
]
},
{
"perId" : "333",
"perName" : "呵呵呵",
"certifications" : [
{
"certNo" : "02345629",
"regType" : "021",
"regMajor" : "120"
},
{
"certNo" : "03445639",
"regType" : "041",
"regMajor" : "124"
}
]
}
],
"createDate" : ISODate("2020-07-22T12:24:14.520Z"),
"lastUpdate" : ISODate("2020-07-22T12:24:14.520Z")
}
在当前我们选择的更新方法之前,如果对上述文档进行更新要考虑很多方面。1.certifications里的数组变动更新 2.personCerts数组下的非certifications数组变动更新 3.单纯的 certifications 增加 4.单纯的 personCerts 增加
一.针对 certifications 里的数组变动更新,这个主要在于查询语句的写法,所有嵌套文档更新,如果需要嵌套关系,则必须使用elematch,这种更新方式在我之前的一篇博客中有写,主要是用 mongodb的 $[<identifier>]
如果我只想更新 perId = 333,certNo= 02345629 中的regMajor 为 000 ,mongo语句如下
db.getCollection("db_test").update(
{
$and: [
{
"_id": "1"
},
{
"personCerts": {
$elemMatch: {
$and: [{
"perId": "333"
}, {
"certifications": {
"$elemMatch": {
"certNo": "02345629"
}
}
}]
}
}
}
]
},
{
$set: {
"personCerts.$.certifications.$[certification].regMajor": "000"
}
},
{
arrayFilters: [{
"certification.certNo": "02345629"
}],
multi: true
}
)
java写法
Bson filters = Filters.and(Filters.eq("_id","1"),
Filters.elemMatch(
"personCerts",
Filters.and(
Filters.eq("perId","333"),
Filters.elemMatch("certifications",Filters.eq("certNo","02345629"))
)
)
);
Bson update = Updates.set("personCerts.$.certifications.$[certification].regMajor","OOO");
Bson filter = Filters.eq("certification.certNo", "02345629");
UpdateOptions updateOptions = new UpdateOptions().arrayFilters(Collections.singletonList(filter));
MongoCollection<Document> collection = mongoTemplate.getDb().getCollection("db_test");
documents.updateOne(filters,update,updateOptions);
二.针对personCerts数组下的非certifications数组变动更新。这回我想将perId = 111的 人员名称 perName 更新为 吼吼吼
这里也是用的 $[<identifier>] ,mongo写法如下
db.getCollection("db_test").update(
{
$and: [
{
"_id": "1"
},
{
"personCerts": {
$elemMatch: {
"perId": "111"
}
}
}
]
},
{
$set: {
"personCerts.$[personCert].perName": "吼吼吼"
}
},
{
arrayFilters: [{
"personCert.perId": "111"
}],
multi: true
}
)
java写法
Bson filters = Filters.and(Filters.eq("_id","1"),
Filters.elemMatch(
"personCerts",
Filters.eq("perId","111")
)
);
Bson update = Updates.set("personCerts.$[personCert].perName","吼吼吼");
Bson filter = Filters.eq("personCert.perId", "111");
UpdateOptions updateOptions = new UpdateOptions().arrayFilters(Collections.singletonList(filter));
MongoCollection<Document> collection = mongoTemplate.getDb().getCollection("db_test");
documents.updateOne(filters,update,updateOptions);
三.单纯的 certifications 增加 ,这属于嵌套数组的追加
db.getCollection("db_test").update(
{
$and: [
{
"_id": "1"
},
{
"personCerts": {
$elemMatch: {
"perId": "111"
}
}
}
]
},
{
$push: {
"personCerts.$.certifications": {
"certNo" : "34546546",
"regType" : "546",
"regMajor" : "433"
}
}
},
true
)
此处的push 如果用addToSet 代替的话,那么如果新加的数组元素与之前的相同,则不会新增,即addToSet 有去重的功能
java 写法
Map<String,Object> certification = new HashMap<>();
certification .put("certNo","34546546");
certification .put("regType","546");
certification .put("regMajor","433");
Bson filters = Filters.and(Filters.eq("_id","1"),
Filters.elemMatch(
"personCerts",
Filters.eq("perId","111")
)
);
Bson update = Updates.push("personCerts.$.certifications",certification);
MongoCollection<Document> collection = mongoTemplate.getDb().getCollection("db_test");
collection.updateOne(filters,update,new UpdateOptions().upsert(true));
四.单纯的 personCerts 追加,这就很简单了
mngodb写法
db.getCollection("db_test").update(
{
$and: [
{
"_id": "1"
}
]
},
{
$addToSet: {
"personCerts": {
"perId": "444",
"perName": "呵呵呵",
"certifications": [
{
"regMajor": "3453",
"certNo": "7687"
"regType": "43534"
}
]
}
}
},
true
)
java写法
Map<String,Object> personCerts = new HashMap<>();
personCerts.put("perId","444");
personCerts.put("perName","呵呵呵");
List<Map<String,Object>> certifications = new ArrayList<>();
Map<String,Object> map = new HashMap<>();
map.put("regMajor":"3453");
map.put("certNo":"7687");
map.put("regType":"43534");
certifications.add(map);
personCerts.put("certifications",certifications);
Bson filters = Filters.eq("_id","1");
Bson update = Updates.push("personCerts",personCerts );
MongoCollection<Document> collection = mongoTemplate.getDb().getCollection("db_test");
collection.updateOne(filters,update,new UpdateOptions().upsert(true));