概要

本文主要讲述在 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. React事件用法

    一.事件处理函数的使用 1.1 绑定事件处理函数 1.2 使用 <HelloWorld onClick={this.handleClick}/> 大括号中指定的是this对象即当前组件引用 ...

  2. U盘还原系统

    相信现在不少的人已经开始使用U盘作为启动盘来安装系统,说起来这可比用光盘装系统可是方便多了.毕竟U盘可以随身携带,至于光盘嘛,就不多说了.       可是还有许多人对U盘安装系统还是有些陌生的感觉. ...

  3. vue tab栏缓存解决跳转页面后返回的状态保持

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8& ...

  4. C# 比较两张图片是否完全相同

    本文演示如何比较两张图片是否完全相同. (注意:如果是比较两张图片是否相似,则比较复杂,涉及到机器学习) 方法一:把图片保存到内存流中,然后转化成 Base64 字符串进行比较 using Syste ...

  5. 【CSS3】loading动画

    HTML: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  6. H3C 帧中继协议栈

  7. linux 字符设备注册

    如我们提过的, 内核在内部使用类型 struct cdev 的结构来代表字符设备. 在内核调用你 的设备操作前, 你编写分配并注册一个或几个这些结构. [11] 11为此, 你的代码应当包含 < ...

  8. mysql导入文件出现Data truncated for column 'xxx' at row 1的原因

    mysql导入文件的时候很容易出现"Data truncated for column 'xxx' at row x",其中字符串里的xxx和x是指具体的列和行数. 有时候,这是因 ...

  9. Spring Security 5中 PasswordEncoder的使用

    在最新的 Spring Security 5发布版本中, 出于安全性的考虑调整了PasswordEncoder的实现与使用策略. 1.以前常用的实现 StandardPasswordEncoder, ...

  10. H3C FTP配置示例