概要

本文主要讲述在 mongodb 中,怎么更新嵌套数组的值。

使用$更新数组

  1. 基本语法  { "<array>.$" : value }
  2. 可以用于:update, findAndUpdate 等方法
  3. $是一个占位符一样的存在。代表被匹配的数组中的一个元素
  4. 可以匹配一个数组,匹配多个是会异常  index 0: 2 - Too many positional (i.e. '$') elements found in path ... ,即:只能在一层嵌套的数组中使用 $
  5. 示例 
    db.collection.update(
    { <array>: value ... },
    { <update operator>: { "<array>.$" : value } }
    )

测试

  1.     创建一个测试数据

    for (let i = 0; i < 3; i++) {
    let data = {
    name1_1: 'test' + i,
    arr_1: [{
    a: i,
    b: 2
    }, {
    a: i + 1,
    b: 2
    }]
    };
    db.nestedUpdate.insert(data);
    }

    创建数据脚本

    数据截图:

  2. 我想更新arr_1数组中,a = 1 的对象,更新为 {a:11,b:12} 运行更新代码,如下:
    db.nestedUpdate.updateMany({
    'arr_1.a': 1
    }, {
    $set: {
    'arr_1.$.a': 11,
    'arr_1.$.b': 12,
    }
    })

    运行后数据截图:

  3.   针对上述结构,更新 a= 11 的对象值(与上面不同,上面是更新对象里面的一个值),运行一下代码:
    db.nestedUpdate.updateMany({
    'arr_1.a': 11
    }, {
    $set: {
       'arr_1.$': {a:11, c:[1,2,3]}
    } })

    运行结果:

  4. 继续编辑,修改 arr_1.c 的元素,很容易想到如下:

    db.nestedUpdate.updateMany({
    'arr_1.c': 1
    }, {
    $set: {
    'arr_1.$.$': 11,
    }
    })

    然而,最终的运行结果却是: [Error] index 0: 2 - Too many positional (i.e. '$') elements found in path 'arr_1.$.$'

    那么,我想更新数组中的数组下的一个元素这么办呢?下面介绍两种方法:1、遍历数组修改,2、使用 arrayFilter。个人推荐 arrayFilter 方式。

.find.foreach + save (循环判断保存法)

  1. 通过 .find 找到满足条件的集合,(但只能找到根节点)
  2. 遍历需要修改的节点,修改其值,(先遍历arr_1, 在遍历 arr_1.c)
  3. 把修改完成的对象,通过 save 方法更新回数据库。
  4. 代码如下
    // 查找所有
    var all1 = db.nestedUpdate.find({});
    all1.forEach(function(it) {
    var modified = false;
    // 遍历 arr_1
    for (var i = 0; i < it.arr_1.length; ++i) {
    var ac1 = it.arr_1[i];
    // 判断需要修改的
    if (ac1.c && ac1.c.length > 0 && ac1.c[0] == 1) {
    ac1.c[0] = 1111;
    modified = true;
    }
    } if (modified) {
    db.nestedUpdate.save(it);
    }
    })

利用arrayFilter

  • 基本语法
db.collection.updateMany(
{ <query conditions> },
{ <update operator>: { "<array>.$[<identifier>]" : value } },
{ arrayFilters: [ { <identifier>: <condition> } ] }
)

注意

  • arrayFilter 数组中的顶级字段不能重复,如下:出现了两个 idx0,运行报错 index 0: 9 - Found multiple array filters with the same top-level field name idx0

    db.nestedUpdate.updateMany({}, {
    $set: {
    'arr_1.$[idx0].c.$[idx1]': 1
    }
    }, {
    arrayFilters: [
    {
    // idx0 满足条件: 需存在 c 字段
    'idx0.c': {
    $exists: true
    },
    },
    {
    'idx0.a': 1,
    },
    {
    // idx1: 满足 值为 111
    'idx1': 1111
    }
    ]
    });
    > [Error] index 0: 9 - Found multiple array filters with the same top-level field name idx0
    at line 1, column 1
  • arrayFilter 中可以嵌套条件,如:
    db.nestedUpdate.updateMany({}, {
    $set: {
    'arr_1.$[idx0].c.$[idx1]': 1
    }
    }, {
    arrayFilters: [
    {
    // idx0 满足条件: 需存在 c 字段
    'idx0.c': {
    $exists: true
    },
    'idx0.a': 1,
    },
    {
    // idx1: 满足 值为 111
    'idx1': 1111
    }
    ]
    }); // 或 db.nestedUpdate.updateMany({}, {
    $set: {
    'arr_1.$[idx0].c.$[idx1]': 1
    }
    }, {
    arrayFilters: [
    {
    // idx0 满足条件: 需存在 c 字段
    idx0: {
    c: {
    $exists: true
    },
    a: 1
    }
    },
    {
    // idx1: 满足 值为 111
    'idx1': 1111
    }
    ]
    });
  • arrayFilter 必须包含所有的索引的条件。否则出现错误 [Error] index 0: 2 - No array filter found for identifier 'idx2' in path 'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]' 
    db.nestedUpdate1.updateMany({}, {
    $set: {
    'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]': null
    }
    }, {
    arrayFilters: [
    {
    // idx1: 满足 name <= 1
    'idx1.name': {
    $lte: 1
    }
    }, ]
    })
    > [Error] index 0: 2 - No array filter found for identifier 'idx2' in path 'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]'
    at line 1, column 1
    > 时间: 0.003s

    完整代码

  • $[idx] 中的idx 可以自定义名字,只需要arrayFilter中名字一样就可以,如 $[i], $[j]
  • 不止updateMany可以用,update、findAndUpdate、findAndModify 等也可以用
  • 可以与$[] 一起使用,需保证数组中的所有元素都满足后面的条件,如:
    db.nestedUpdate1.updateMany({}, {
    $set: {
    'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]': null
    }
    }, {
    arrayFilters: [
    {
    // idx1: 满足 name <= 1
    'idx1.name': {
    $lte: 1
    }
    },
    {
    idx2: 1
    }
    ]
    })

    运行示意:

mongodb 更新嵌套数组的值的更多相关文章

  1. C# .NET Core 3.1中使用 MongoDB.Driver 更新嵌套数组元素和关联的一些坑

    C# .NET Core 3.1中使用 MongoDB.Driver 更新数组元素和关联的一些坑 前言: 由于工作的原因,使用的数据库由原来的 关系型数据库 MySQL.SQL Server 变成了 ...

  2. MongoDB按照嵌套数组中的map的某个key无法正常排序的问题

    前阵子同事有一个需求: 在一个数组嵌套map的结构中,首先按照map中的某个key进行筛选,再按照map中的某个key进行排序,但是奇怪的是数据总是乱序的. 再检查了代码和数据之后并没有发现什么错误, ...

  3. 【MongoDB】嵌套数组查询方案

    From:http://stackoverflow.com/questions/12629692/querying-an-array-of-arrays-in-mongodb 数据 db.multiA ...

  4. MongoDB学习笔记~官方驱动嵌套数组对象的更新

    回到目录 对于数组对象mongodb本身是支持的,不过对于数组的更新,mongodb的Csharp驱动目前只支持一级,即你的对象里包含数组,而数组又包括数组,这表示两层,这在更新子数组时,Csharp ...

  5. Vue 嵌套数组 数组更新视图不更新

    关于Vue的响应式原理,可以看官方文档或其他资料, https://www.jianshu.com/p/34de360d6035 data里定义了一个数组arr,数组的元素可以是同样格式的数组arrC ...

  6. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 更新和删除)--学习笔记

    2.5.4 MongoDB -- 更新和删除 整体更新 更新字段 字段操作 数组操作 删除 https://docs.mongodb.com/manual/reference/operator/upd ...

  7. [C#]想说一说嵌套数组

    今天早上,随感而发,随便写了点东西.结果下午的时候看了看评论,吓我一跳.估计是不是写代码的人看散文看得太少了,还是因为现在的人读的书太少了,似乎有有些大惊小怪. 关于Y美女,我声明一下,尽管她很脱俗, ...

  8. [jQ/PHP]使用JS数组储值的两种情况(提交PHP处理)

    ---------------------------------------------------------------------------------------------------- ...

  9. MongoDB——更新操作(Update)c#实现

    c#实现 Mongodb存储[文档局部更新] 如下: 递归更新字段  ,构建UpdateDefinition   /// <summary>   /// 构建更新操作定义   /// &l ...

随机推荐

  1. hdu 4179 Difficult Routes (SP)

    Problem - 4179 坑了我一个晚上的SP题. 题意是,给出若干空间中的点,给出其中某些点之间是有直线线段路径相连的.要求求出一条从s开始到t结束的路径,它的难度是d.难度的计算是空间线段两点 ...

  2. 解决电脑性能一般,打开webstorm后,电脑比较卡的问题

    刚到一公司实习,要求使用webstrom开发前端,但安装后发现自己的电脑很卡,特别是在运行项目时,卡的不要不要的. 后来,发现一奇淫技巧,用sublime代替webstrom,但是没法启动项目啊 找到 ...

  3. 深入Java线程管理(五):线程池

    这几天主要是狂看源程序,在弥补了一些以前知识空白的同时,也学会了不少新的知识(比如 NIO),或者称为新技术吧. 线程池就是其中之一,一提到线程,我们会想到以前<操作系统>的生产者与消费者 ...

  4. axis2 wsdl2java工具

    wsdl2java工具使用方法描述: C:\Users\Administrator>wsdl2java -h Using AXIS2_HOME: E:\Apache_Projects\axis2 ...

  5. Python--day42--MySQL外键定义及创建

    什么是外键? 外键的创建:constraint 外键名 foregin key ("表1值1",“ 表1值2”) references 表2的名字(“值1”)

  6. java 布局管理器

    容器中的组件的排放方式,就是布局. 常见的布局管理器: FlowLayout(流式布局管理器)//目前最常用的 从左到右的顺序排列. Panel默认的布局管理器. BorderLayout(边界布局管 ...

  7. 【7003】&&【a203】合并多项式

    Time Limit: 3 second Memory Limit: 2 MB 问题描述      求两个一元多项式的和.输入多项式方式为:多项式项数.每项系数和指数,按指数从大到小的顺序输入.输出多 ...

  8. 2019年第二阶段我要变强个人训练赛第八场 B.序列(seq)

    传送门 B.序列(seq) •题目描述 给出一个长度为n的序列a,每次对序列进行一下的某一个操作. •输入 第一行两个整数n,q表示序列长度和操作个数. 接下来一行n个数,表示序列a. 接下来q行表示 ...

  9. vue-learning:34 - component - 内置组件 - 动态组件component 和 is属性

    component动态组件 / is属性 让多个组件使用同一个挂载点,并动态切换,这就是动态组件. 必要条件: 组件标签使用<component></component> 动态 ...

  10. 看到两道小学数学题,实在是解不动,用js写了一下

    把一个自然数的约数(除去它本身)按照从小到大的顺序写在它的左边,可以得到一个多位数,比如6的约数是1,2,3,写成一个多位数是1236,假如这个多位数中,没有直复数字,那么我们你这个多位数是唯一的.请 ...