这些MongoDB的隐藏操作你真的都掌握了吗?反正我是刚知道
背景
最近公司系统还原用户时偶尔会出现部分用户信息未还原成功的问题,作为开发人员,最头疼的不是代码存在bug,而是测试发现了bug,但一旦我去重现,它就不见了。Are you kidding me?
经过漫长的沟通与尝试,终于发现了端倪,这个问题只有在多人同时操作修改同一用户信息时才会出现。
哦,那你死定了,小bug。
分析
经过短暂的代码review,发现还原用户时,代码中会先把用户获取出来,然后修改用户信息,最后再将修改后的用户更新至数据库中。
var user1 = collection.Find(x => x.Id == "user1").FirstOrDefault();
user1.Name = "B";
collection.ReplaceOneAsync(x => x.Id == "user1", user1);
这就导致代码并发运行时,后面的可能覆盖前方的操作。
如下图操作1及操作2执行结束后,数据库中用户1的名称为A,年龄为18;操作1的修改用户名称为B被覆盖.

所以我们需要采用原子操作来修改用户信息,我们调整代码如下
UpdateDefinition<Persion> update = Builders<Persion>.Update.Set(y => y.Name, "B");
collection.UpdateOne(x => x.Id == "user1", update);
这样就把修改操作交给数据库来执行,仅修改要修改的属性,避免操作互相影响;
看到这里有的大神就会吐槽,这么简单的东西也好意思拿来说,请在耐心往下看,重点在下边。
重点
如果我们的数据结构类似这样:
/// <summary>
/// 人
/// </summary>
[BsonIgnoreExtraElements]
public class Persion : BaseEntity
{
/// <summary>
/// 名称
/// </summary>
[BsonElement("name")]
public string Name { get; set; } /// <summary>
/// 年龄
/// </summary>
[BsonElement("age")]
public int Age { get; set; } /// <summary>
/// 亲戚
/// </summary>
[BsonElement("relatives")]
public List<Relative> Relatives { get; set; } }
/// <summary>
/// 亲属
/// </summary>
public class Relative
{
/// <summary>
/// 名称
/// </summary>
[BsonElement("name")]
public string Name { get; set; } /// <summary>
/// 与本人关系
/// </summary>
[BsonElement("relationship")]
public Relationship Relationship { get; set; }
}
/// <summary>
/// 与本人关系
/// </summary>
public enum Relationship
{
/// <summary>
/// 爸爸
/// </summary>
father = ,
/// <summary>
/// 妈妈
/// </summary>
mother = ,
/// <summary>
/// 儿子
/// </summary>
son = ,
/// <summary>
/// 女儿
/// </summary>
daughter = ,
/// <summary>
/// 不明
/// </summary>
unknow =
}
如果我们想更新名称为“赵小明”的人的名称为“赵刚”的亲戚与本人关系为“爸爸”,请考虑,应该怎么处理。
注意:人的亲戚可以有多个,所以是List。
这时我们就用到了ArrayFilters对象,其存在于UpdateOptions中,如果没有系统的看过MongoDB的接口,我相信大部分人都会忽略它。
好了,废话不多说,让我们来看看它的用法吧
FilterDefinition<Persion> filter = Builders<Persion>.Filter.Where(x => x.Name == "赵小明" && x.Relatives != null && x.Relatives.Count > );
UpdateDefinition<Persion> update = Builders<Persion>.Update.Set("relatives.$[i].relationship", Relationship.father);
var option = new UpdateOptions()
{
ArrayFilters = new List<ArrayFilterDefinition> {
new JsonArrayFilterDefinition<Relationship>("{'i.name': '赵刚'}")
}
};
collection.UpdateMany(filter, update, option);
可以看到,我们先生成一个查询条件,名称为“赵小明”,存在亲戚的人;
然后更新其"relatives.$[i].relationship"属性,为Relationship.father,其中的$[i]为占位符;
再生成一个决定$[i]值的JsonArrayFilterDefinition<Relationship>("{'i.name': '赵刚'}");
最后用这些条件来更新数据库。
引申
好了,更新是实现了,那有求知欲的小伙伴就会想查询怎么办呢?
这还不简单,一行语句就搞定了
var user = collection.Find(x => x.Name == "赵小明" && x.Relatives != null && x.Relatives.Count > 0 && x.Relatives.Exists(y => y.Name == "赵刚")).FirstOrDefault();
没错,但如果此人存在几千万个亲戚(现实生活中怎么可能,笑),我只需要其与一个名为“赵刚”的亲戚的关系,不想把整个对象都加载到内存中怎么办?
这时我们就需要用到ProjectionDefinitionBuilder对象了,
FilterDefinition<Persion> filter = Builders<Persion>.Filter.Where(x => x.Name == "赵小明" && x.Relatives != null && x.Relatives.Count > ); var findOptions = new FindOptions<Persion, Relative>()
{
Projection = new ProjectionDefinitionBuilder<Persion>().Expression(x => x.Relatives.FirstOrDefault(r => r.Name != "赵刚"))
}; Relative cursor = collection.FindSync(filter, findOptions).FirstOrDefault();
我们就得到了我们想要的亲戚对象,而不是包含几千万亲戚信息的完整Persion对象了。
结语
作为一名博客萌新,我只是将我遇到的问题总结下来并分享给大家,有不对的地方,务必帮忙指正。
当然上面的内容对于大佬来说可能是常规操作,但如果对你有一点点用处,请点赞,评论,并关注下。
后面我会将我在工作学习中遇到的有趣的问题分享给大家,谢谢!!!
这些MongoDB的隐藏操作你真的都掌握了吗?反正我是刚知道的更多相关文章
- MongoDB数据库简单操作
之前学过的有mysql数据库,现在我们学习一种非关系型数据库 一.简介 MongoDB是一款强大.灵活.且易于扩展的通用型数据库 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数 ...
- 【翻译】MongoDB指南/CRUD操作(二)
[原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(二) 主要内容: 更新文档,删除文档,批量写操作,SQL与MongoDB映射图,读隔离(读关 ...
- 【翻译】MongoDB指南/CRUD操作(一)
[原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(一) 主要内容:CRUD操作简介,插入文档,查询文档. CRUD操作包括创建.读取.更新和删 ...
- MongoDB的CRUD操作
1. 前言 在上一篇文章中,我们介绍了MongoDB.现在,我们来看下如何在MongoDB中进行常规的CRUD操作.毕竟,作为一个存储系统,它的基本功能就是对数据进行增删改查操作. MongoDB中的 ...
- MongoDB各种查询操作详解
这篇文章主要介绍了MongoDB各种查询操作详解,包括比较查询.关联查询.数组查询等,需要的朋友可以参考下 一.find操作 MongoDB中使用find来进行查询,通过指定find的第一个参数可 ...
- Javascript的DOM操作 - 你真的了解吗?
摘要 想稍微系统的说说对于DOM的操作,把Javascript和jQuery常用操作DOM的内容归纳成思维导图方便阅读,同时加入性能上的一些问题. 前言 在前端开发的过程中,javascript极为重 ...
- mongodb学习03 操作详解
插入文档 db.test.insert({"name":"jinks"}); 批量插入 db.test.insert([{}, {}, {}]); 一次批量插入 ...
- mongodb的常用操作
对于nosql之前工作中有用到bekerlydb,最近开始了解mongodb,先简单写下mongodb的一些常用操作,当是个总结: 1.mongodb使用数据库(database)和集合(collec ...
- openerp 经典收藏 通过view实现字段的只读、隐藏操作(转载)
通过view实现字段的只读.隐藏操作 原文地址:http://cn.openerp.cn/view_groups/ 在OpenERP V7视图(ir.ui.view)多了一个非常有用的字段(group ...
随机推荐
- EmguCV C# 安装入门教程
EmguCv3的安装. EmguCv3下载网址 http://sourceforge.net/projects/emgucv/files/emgucv/3.0.0/ 推荐下载第一个: 点击direct ...
- 17)将index.php中的代码放到Framework中封装起来
目录结构: 发生改动的类代码: 新增类:Framework.class.php <?php /** * Created by PhpStorm. * User: Interact * Date: ...
- java 内存溢出-与gc
感谢原作者 在日常中我们经常遇到这样的错误:java.lang.OutOfMemoryError: Java heap space. 但是除了heap space 的OutOfMemoryError, ...
- Oracle 11g 静默安装过程(centos7)
开启机器,本次实例分配的ip是:192.168.3.197(Xshell ssh连接) 2 安装unzip 工具.vim编辑器(个人习惯,vi也可以) 3 在/etc/hosts文件中添加本机IP跟主 ...
- HDU-3579-Hello Kiki (利用拓展欧几里得求同余方程组)
设 ans 为满足前 n - 1个同余方程的解,lcm是前n - 1个同余方程模的最小公倍数,求前n个同余方程组的解的过程如下: ①设lcm * x + ans为前n个同余方程组的解,lcm * x ...
- 吴裕雄--天生自然HTML学习笔记:HTML 标题
在 HTML 文档中,标题很重要. HTML 标题 标题(Heading)是通过 <h1> - <h6> 标签进行定义的. <h1> 定义最大的标题. <h6 ...
- js 实现排序算法 -- 选择排序(Selection Sort)
原文: 十大经典排序算法(动图演示) 选择排序(Selection Sort) 选择排序(Selection-sort)是一种简单直观的排序算法.它的工作原理:首先在未排序序列中找到最小(大)元素,存 ...
- 将js进行到底:node学习5
HTTP开发之Connect工具集--中间件 继学习node.js的TCP API和HTTP API之后,node.js web开发进入了正轨,但这就好像Java的servlet一样,我们不可能使用最 ...
- kubernetes集群中的pause容器
昨天晚上搭建好了k8s多主集群,启动了一个nginx的pod,然而每启动一个pod就伴随这一个pause容器,考虑到之前在做kubelet的systemd unit文件时有见到: 1 2 3 4 5 ...
- Java-Springboot-集成spring-security简单示例(Version-springboot-2-1-3-RELEASE
使用Idea的Spring Initializr或者SpringBoot官网下载quickstart 添加依赖 1234 <dependency><groupId>org.sp ...