文章目录
1.前言
最近遇到了一个需求,需要在系统中配置用户的自定义字段,考虑到后续维护的灵活性,选择了使用MongoDB来持久化自定义字段数据,在做这个需求的过程中,遇到了同一个数据中有多层嵌套数组的增删改问题,在网上查阅了大部分的资料说的不是很全,于是在处理好这个需求之后,整理并记录一下处理中使用到的一些技术细节,以供大家参考。
本文包含了一级和二级嵌套数组的操作,篇幅较长,如果只想了解在生产服务中如何应用,可以直接查看目录中的 4.Mongo Template 操作实践
2.数据准备
首先是数据结构准备,这里我处理掉了和公司有关的信息,下面展示的是一个简单的Demo结构,可以看到的是在自定义字段 userDefinedFields 是一个数组类型的数据,表示同一个用户可以有多个自定义字段。自定义字段的类型type如果为 select ,则还会包含下列框的选项字段 options ,也是一个数组,此时就出现了两层的嵌套数组了。
{
"_id":1,
"userId":"1",
"userDefinedFields":[
{
"key":"111",
"name":"自定义字段1",
"type":"input"
},
{
"key":"222",
"name":"自定义字段2",
"type":"select",
"options":[
{
"optionKey":"11",
"optionValue":"选项1"
},
{
"optionKey":"22",
"optionValue":"选项2"
}
]
}
]
}
现在遇到的问题就是,不想一个大JSON来对这条数据做全量操作,只想针对数组中的某一个元素中的字段做修改,如何才能实现呢?
3.Mongo Shell操作实践
查询MongoDB的官方文档中与数组更新相关的部分:《Array Update Operators》,可以看到如下的一些操作方式。

接下来就按照文档的指引,完成下面的操作。
3.1.第一层数组操作
3.1.1.新增元素
在userDefinedFields中添加数据,即新建一个自定义字段。可以使用 $push 或 $addToSet,两者的区别是 $addToSet 添加的元素不能在数组中已存在,而$push没有限制,此处用$push演示。
db.user_defined_field.updateMany(
{
_id:1},
{
$push:{
"userDefinedFields":{
"key":"333","name":"自定义字段3","type":"input"}}}
);
此时的数据会如下:
{
"_id":1,
"userId":"1",
"userDefinedFields":[
{
"key":"111",
"name":"自定义字段1",
"type":"input"
},
{
"key":"222",
"name":"自定义字段2",
"type":"select",
"options":[
{
"optionKey":"11",
"optionValue":"选项1"
},
{
"optionKey":"22",
"optionValue":"选项2"
}
]
},
{
"key":"333",
"name":"自定义字段3",
"type":"input"
}
]
}
3.1.2.修改元素
修改元素需要使用到 $,$[],两者的区别在于 $ 只修改条件匹配的第一个元素 $[]是修改条件匹配的全部元素。
// 第一层数组修改
db.user_defined_field.updateMany(
{
_id:1,"userDefinedFields.type":"input"},
{
$set:{
"userDefinedFields.$.name":"测试$"}}
);
此时只修改了第一个结果(减少篇幅,后续的数据从数组开始展示,外层的id不展示了):

3.1.2.1.批量修改元素中的坑
再尝试批量修改元素:
db.user_defined_field.updateMany(
{
_id:1,"userDefinedFields.type":"input"},
{
$set:{
"userDefinedFields.$[].name":"测试$[]"}}
);

如上图所示,type 为 select 的元素也被修改了,也就是说"userDefinedFields.type":"input"并没有生效,这显然是不符合要求的。
查阅了MongoDB文档,这种更新需要使用 $[<identifier>] 来标识待查询的条件,$[]具体应该怎么用呢?
3.1.3.使用$[<identifier>]做批量修改
先看一下语法:
db.collectio

本文介绍了在MongoDB中处理嵌套数组的增删改操作,包括MongoShell和MongoTemplate的实践,重点讲解了$[<identifier>]和arrayFilters的使用,以解决只修改特定元素字段的需求。文章提供了一级和二级数组操作的示例,并给出了Java代码实现。

717

被折叠的 条评论
为什么被折叠?



