这些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 ...
随机推荐
- interrupt 停止线程
该方法只是给线程设置了一个停止的标记 并不是真正的立即停止线程 interrupted() 测试当前线程是否已经中断 isInterrupted() 测试线程是否已经中断 停止线程的方法: .异常法 ...
- AngularJS中格式化日期为指定格式字符串
var date = $filter('date')(new Date(),'MM/dd/yyyy');
- mongo的基本命令操作
基本用法学习:https://www.runoob.com/mongodb/mongodb-create-database.html MongoDB数据库基本用法 show dbs:显示数据库列表 s ...
- Nginx笔记总结十九:nginx + fancy实现漂亮的索引目录
编译:./configure --prefix=/usr/local/nginx --add-module=../ngx-fancyindex-master 配置: location / { fanc ...
- 实战:Zabbix 3.4邮件报警配置
环境:CentOS 7 + Zabbix 3.4 如果只是监测并不能满足需求,还需要通过邮件的方式对问题进行报警.接下来进行实战操作: 一.安装邮件发送工具 mailx 如果CentOS 有邮件服务, ...
- js实现键盘数字输入
<html> <head> <meta charset="UTF-8"> </head> <script> functi ...
- xshell 常用命令1
date命令 date命令是显示或设置系统时间与日期. 很多shell脚本里面需要打印不同格式的时间或日期,以及要根据时间和日期执行操作.延时通常用于脚本执行过程中提供一段等待的时间.日期可以以多种格 ...
- 腾讯入股Snap,能救“阅后即焚”的命吗?
互联网社交的强大包容性,让各种社交形式都能有着较多的受众群体.普适性极广的QQ.微信."脸谱":专攻陌生人社交的陌陌:让人们发布意见的微博--当然也少不了"阅 ...
- Android空包签名
空包签名 搜狗.优亿等Android市场,上传应用需要提供一个与要上传的应用相同签名的空包.这个空包是相应官方市场提供的,下载好之后需要使用命令行进行签名.具命令如下: 1 jarsigner -ve ...
- 寄生or独立 中国代工厂的悲惨抉择
2015年苹果.三星.国产手机依旧外表光鲜,最起码,从出货量上看,他们的日子过得还不错,年终奖应该是能发得出来,但这些光鲜的品牌商背后,是一个个悲惨的代工厂,以及一个又一个"一将功成万骨枯& ...