这些MongoDB的隐藏操作你真的都掌握了吗?反正我是刚知道

这些MongoDB的隐藏操作你真的都掌握了吗?反正我是刚知道背景 最近公司系统还原用户时偶尔会出现部分用户信息未还原成功的问题,作为开发人员,最头疼的不是代码存在bug,而是测试发现了bug,但一旦我去重现,它就不见了。Are you kidding me?

这些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);

代码100分

这就导致代码并发运行时,后面的可能覆盖前方的操作。

如下图操作1及操作2执行结束后,数据库中用户1的名称为A,年龄为18;操作1的修改用户名称为B被覆盖.

 这些MongoDB的隐藏操作你真的都掌握了吗?反正我是刚知道

所以我们需要采用原子操作来修改用户信息,我们调整代码如下

代码100分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; }

}

代码100分/// <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 = 0,
    /// <summary>
    /// 妈妈
    /// </summary>
    mother = 1,
    /// <summary>
    /// 儿子
    /// </summary>
    son = 2,
    /// <summary>
    /// 女儿
    /// </summary>
    daughter = 3,
    /// <summary>
    /// 不明
    /// </summary>
    unknow = 100
}

如果我们想更新名称为“赵小明”的人的名称为“赵刚”的亲戚与本人关系为“爸爸”,请考虑,应该怎么处理。

注意:人的亲戚可以有多个,所以是List。

这时我们就用到了ArrayFilters对象,其存在于UpdateOptions中,如果没有系统的看过MongoDB的接口,我相信大部分人都会忽略它。

好了,废话不多说,让我们来看看它的用法吧

FilterDefinition<Persion> filter = Builders<Persion>.Filter.Where(x => x.Name == "赵小明" && x.Relatives != null && x.Relatives.Count > 0);

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 > 0);

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对象了。

结语

作为一名博客萌新,我只是将我遇到的问题总结下来并分享给大家,有不对的地方,务必帮忙指正。

当然上面的内容对于大佬来说可能是常规操作,但如果对你有一点点用处,请点赞,评论,并关注下。

后面我会将我在工作学习中遇到的有趣的问题分享给大家,谢谢!!!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/9516.html

(0)
上一篇 2023-02-06
下一篇 2023-02-06

相关推荐

  • Python Dictionary:高效存储和快速查找数据的神器

    Python Dictionary:高效存储和快速查找数据的神器Python Dictionary(字典),是Python内置的一种数据类型,它提供了一种非常高效的方式来存储和查找数据。和列表(List)一样,Python Dictionary也是可变的,但列表可以通过位置来索引数据,而字典则可以用任意不可变的(immutable)类型作为其键(key)。

    2024-01-12
    116
  • Python的锚点用法

    Python的锚点用法在网页设计中,锚点是指将文本或图像与文档中其他部分相关联的一种超链接,通常用于快速定位到网页的特定部分。Python语言作为一种广泛应用的编程语言,其内置的a href=”#anchor”锚点功能/a可以帮助我们更好地管理和组织代码,提高代码的可读性和可维护性。

    2023-12-17
    117
  • PostgreSQL 数据库开发规范「终于解决」

    PostgreSQL 数据库开发规范「终于解决」PostgreSQL的功能非常强大,但是要把PostgreSQL用好,开发人员是非常关键的。

    下面将针对PostgreSQL数据库原理与特性,输出一份开发规范,希望可以减少大家在使用PostgreS

    2023-06-11
    137
  • navicat导入oracle数据_cmd导入dmp文件命令

    navicat导入oracle数据_cmd导入dmp文件命令1. 2,点击其他–新建目录–输入目录路径….dmp的目录 3,新建一个表空间, 其他–表空间–新建表空间 点击保存 4…点击数据泵,,数据泵导入 5…点击生成sql,运行, (运

    2023-02-27
    152
  • 详细记录一次stampstime字段引起pxc集群脑裂[亲测有效]

    详细记录一次stampstime字段引起pxc集群脑裂[亲测有效]事故回顾 运维执行导入sql,导入后收到master2和master3节点宕机的报警; 检查集群状态发现master1进入初始化模式,无法读写;master2和master3已经下线; 处理方法 分别

    2023-05-02
    148
  • day10-习题[通俗易懂]

    day10-习题[通俗易懂]习题 1.Homework01 (1) D 没有在别名上加引号(ps:别名的as可以省略) (2) B 判断null或非空不能用不等于号 (3) C 2.Homework02 写出查看de

    2023-06-10
    141
  • 查杀oracle的阻塞「终于解决」

    查杀oracle的阻塞「终于解决」查杀oracle的阻塞 cuihengju8933 2018-07-22 20:12:32 42 收藏 执行以下脚本抓目前的阻塞: select (select username||':&…

    2023-03-15
    164
  • 探究Python编程中的对象

    探究Python编程中的对象在Python编程中,对象(Object)是非常重要的概念。在Python中,所有的数据类型都是以对象的形式存在,每一个对象都具有唯一的标识符(id)、类型(type)和值(value),并且都可以被赋值给一个或多个变量。

    2024-04-07
    81

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注