首页 > 数据库 >.Net下验证MongoDB 的 Linq 模式联合查询是否可用

.Net下验证MongoDB 的 Linq 模式联合查询是否可用

时间:2023-07-04 17:44:11浏览次数:43  
标签:outer MongoDB Linq 查询 project source a2 Net id

MongoDB.Driver 类库提供了 Linq 查询的支持。然而,在使用 Linq 进行联合查询时,是否能够正确转换为 MongoDB 底层的查询语句还有待验证。今天,我将进行实验来验证一下。

输出查询语句

首先,通过订阅 MongoClientSettings 的功能,将查询语句输出。

            var settings = MongoClientSettings.FromConnectionString("mongodb://192.168.11.137:27017");

            settings.ClusterConfigurator = cb => {
                cb.Subscribe<CommandStartedEvent>(e =>
                {
                    Debug.WriteLine( e.Command.ToString());
                });
            };

接下来,实例化 MongoClient 对象。由于我准备测试三个集合的联合查询,所以初始化了三个集合对象,并将它们转换为 Queryable 类型,以便使用 Linq 语句进行查询。

            var client = new MongoClient(settings);
            var database = client.GetDatabase("MyTestDB");

            var userinfos = database.GetCollection<UserInfo>("UserInfo").AsQueryable();
            var ages = database.GetCollection<UserAge>("UserAges").AsQueryable();
            var ageinfos = database.GetCollection<AgeInfo>("AgeInfos").AsQueryable();

简洁版联合查询

先尝试直接使用 SelectMany 查询,看是否支持联合查询。
记得先使用 MongoDB.Driver.Linq 命名空间,否则会报错。

            var data = (from u in userinfos
                         from a in ages
                         where u.Id == a.UserId
                         select u).FirstOrDefault();

运行代码后,data 对象是有值的。实际输出的查询语句如下:

{ "aggregate" : "UserAges", "pipeline" : [], "cursor" : { }, "$db" : "MyTestDB", "lsid" : { "id" : CSUUID("f8e45203-f268-4fe1-9adf-b1071b3baa1f") } }

{ "aggregate" : "UserInfo", "pipeline" : [{ "$project" : { "_v" : { "$map" : { "input" : [{ "_id" : ObjectId("64a264055a5c1963f4f330a0"), "UserId" : ObjectId("6470620ab45534bbc84d41ec"), "Name" : "Jack", "Age" : 0 }], "as" : "a", "in" : { "u" : "$$ROOT", "a" : "$$a" } } }, "_id" : 0 } }, { "$unwind" : "$_v" }, { "$match" : { "$expr" : { "$eq" : ["$_v.u._id", "$_v.a.UserId"] } } }, { "$project" : { "_v" : "$_v.u", "_id" : 0 } }], "cursor" : { }, "$db" : "MyTestDB", "lsid" : { "id" : CSUUID("f8e45203-f268-4fe1-9adf-b1071b3baa1f") }, "$clusterTime" : { "clusterTime" : Timestamp(1688436977, 1), "signature" : { "hash" : new BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }


对于了解 MongoDB 的人来说,可以看出这并不是 MongoDB 的联合查询语句。它实际上是首先将一个表的数据取出,然后与另一个表进行比较。因此,这种方法不能用于联合查询。

Join查询

接下来,我们来看看 Join 查询的语句是什么样的。

            var datas = (from u in userinfos
                         join a in ages on u.Id equals a.UserId into aGroup
                         from a2 in aGroup.DefaultIfEmpty()
                         select new { 
                            User = u,
                            Age = a2
                         }).FirstOrDefault();

输出的查询语句如下:

{ "aggregate" : "UserInfo", "pipeline" : [{ "$project" : { "_outer" : "$$ROOT", "_id" : 0 } }, { "$lookup" : { "from" : "UserAges", "localField" : "_outer._id", "foreignField" : "UserId", "as" : "_inner" } }, { "$project" : { "u" : "$_outer", "aGroup" : "$_inner", "_id" : 0 } }, { "$project" : { "_v" : { "$map" : { "input" : { "$let" : { "vars" : { "source" : "$aGroup" }, "in" : { "$cond" : { "if" : { "$eq" : [{ "$size" : "$$source" }, 0] }, "then" : [{ "_id" : ObjectId("000000000000000000000000"), "UserId" : ObjectId("000000000000000000000000"), "Name" : null, "Age" : 0 }], "else" : "$$source" } } } }, "as" : "a2", "in" : { "User" : "$u", "Age" : "$$a2" } } }, "_id" : 0 } }, { "$unwind" : "$_v" }, { "$limit" : NumberLong(1) }], "cursor" : { }, "$db" : "MyTestDB", "lsid" : { "id" : CSUUID("7eb2b612-b037-430e-b86c-4f349112ba56") } }

这个查询语句看起来是比较标准的 MongoDB 联合查询了。再多加一个表进行 Join 查询,看看输出的语句。

            var datas = (from u in userinfos
                         join a in ages on u.Id equals a.UserId into aGroup
                         from a2 in aGroup.DefaultIfEmpty()
                         join info in ageinfos on a2.Id equals info.AgeId into bGroup
                         from info2 in bGroup.DefaultIfEmpty()
                         select new { 
                            User = u,
                            Age = a2,
                            Info = info2
                         }).FirstOrDefault();

输出查询语句:

{ "aggregate" : "UserInfo", "pipeline" : [{ "$project" : { "_outer" : "$$ROOT", "_id" : 0 } }, { "$lookup" : { "from" : "UserAges", "localField" : "_outer._id", "foreignField" : "UserId", "as" : "_inner" } }, { "$project" : { "u" : "$_outer", "aGroup" : "$_inner", "_id" : 0 } }, { "$project" : { "_v" : { "$map" : { "input" : { "$let" : { "vars" : { "source" : "$aGroup" }, "in" : { "$cond" : { "if" : { "$eq" : [{ "$size" : "$$source" }, 0] }, "then" : [{ "_id" : ObjectId("000000000000000000000000"), "UserId" : ObjectId("000000000000000000000000"), "Name" : null, "Age" : 0 }], "else" : "$$source" } } } }, "as" : "a2", "in" : { "<>h__TransparentIdentifier0" : "$$ROOT", "a2" : "$$a2" } } }, "_id" : 0 } }, { "$unwind" : "$_v" }, { "$project" : { "_outer" : "$_v", "_id" : 0 } }, { "$lookup" : { "from" : "AgeInfos", "localField" : "_outer.a2._id", "foreignField" : "AgeId", "as" : "_inner" } }, { "$project" : { "<>h__TransparentIdentifier1" : "$_outer", "bGroup" : "$_inner", "_id" : 0 } }, { "$project" : { "_v" : { "$map" : { "input" : { "$let" : { "vars" : { "source" : "$bGroup" }, "in" : { "$cond" : { "if" : { "$eq" : [{ "$size" : "$$source" }, 0] }, "then" : [{ "_id" : ObjectId("000000000000000000000000"), "AgeId" : ObjectId("000000000000000000000000"), "CreateTime" : ISODate("0001-01-01T00:00:00Z") }], "else" : "$$source" } } } }, "as" : "info2", "in" : { "User" : "$<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.u", "Age" : "$<>h__TransparentIdentifier1.a2", "Info" : "$$info2" } } }, "_id" : 0 } }, { "$unwind" : "$_v" }, { "$limit" : NumberLong(1) }], "cursor" : { }, "$db" : "MyTestDB", "lsid" : { "id" : CSUUID("bb4e2da5-bedb-4a8e-b1f0-92e5889bc71d") } }

通过三表联合查询,lookup 了两次,应该是正确的。不过里面是否有一些无用并且会影响性能的语法,熟悉 MongoDB 语法的朋友可以来发表一下意见。

标签:outer,MongoDB,Linq,查询,project,source,a2,Net,id
From: https://www.cnblogs.com/IWings/p/17525166.html

相关文章

  • asp.net core如何获取客户端IP地址
    客户端直接访问服务器直接通过HttpContext.Connection.RemoteIpAddress获取客户端Ip[HttpGet][Route("GetClientIP")]publicasyncTask<IActionResult>GetClientIP(){ varip4=HttpContext.Connection.RemoteIpAddress.MapToIPv4(); returnOk(ip4.ToString());}客......
  • 如何将SSL证书从Kubernetes Secrets导出并复原为证书PEM和密钥文件
    首先,您需要使用kubectl工具从Kubernetes导出Secret到一个yaml文件,这通常使用如下命令:kubectlgetsecretmy-secret-oyaml>my-secret.yaml然后我们可以创建一个简单的bash脚本来处理yaml文件并导出证书:#!/bin/bash#解析yaml文件并得到证书内容certData=......
  • 【Netty】「萌新入门」(三)ChannelFuture 与 CloseFuture
    前言本篇博文是《从0到1学习Netty》中入门系列的第三篇博文,主要内容是介绍Netty中ChannelFuture与CloseFuture的使用,解决连接问题与关闭问题,往期系列文章请访问博主的Netty专栏,博文中的所有代码全部收集在博主的GitHub仓库中;连接问题与ChannelFuture在Netty中,所有的......
  • MQTTnet 创建基于 WebSocket 的 Mqtt 服务器
    MQTTnet.Exceptions.MqttProtocolViolationException:Expectedatleast21540bytesbutthereareonly71bytes使用了错误的协议,mqtt有tcp和ws两种连接协议ws://使用1883端口就能正常连接 ......
  • efficienthrnet读取H-2yaml文件
    代码读取配置文件创建的网络['features.0.1.weight:torch.Size([24,3,3,3])','features.0.2.weight:torch.Size([24])','features.0.2.bias:torch.Size([24])','features.1.conv.0.1.weight:torch.Size([24,1,3,3])','features.1.......
  • 读取efficienthrnetH-2预训练模型的网络结构
    ['features.0.1.weight:torch.Size([24,3,3,3])','features.0.2.weight:torch.Size([24])','features.0.2.bias:torch.Size([24])','features.0.2.running_mean:torch.Size([24])','features.0.2.running_var:torch.Size......
  • 哪里需要写哪里,FromServices注入 — ASP.NET CORE
    宗旨:用最少的字,学会最有用的知识!愿景目标:阅读本文您将学会如何运用FromServices的方式进行依赖注入。例子背景:以电脑主机为例子进行讲解,我的电脑主机可以接入外置设备,如:键盘、鼠标。那么键盘又分:PS/2接口类型、USB接口类型、无线类型。鼠标也一样。你在用到ASP.NETCORE依赖注......
  • 记一次 .NET 某工控视觉系统 卡死分析
    一:背景1.讲故事前段时间有位朋友找到我,说他们的工业视觉软件僵死了,让我帮忙看下到底是什么情况,哈哈,其实卡死的问题相对好定位,无非就是看主线程栈嘛,然后就是具体问题具体分析,当然难度大小就看运气了。前几天看一篇文章说现在的.NET程序员不需要学习WinDbg,理由就是有很多好的......
  • 掌握ADO.NET的十个热门技巧
     .NET的数据访问编程模式需要一套新的技巧和最佳方法。ADO.NET提供了一个统一的编程模式和一组公用的类来进行任何类型的数据访问,而不管你用何种语言来开发代码。ADO.NET是全新的,但又与ADO尽可能保持一致,它使编程模式从一个客户端/服务器、基于连接的模式转变到了一个......
  • Netty-LengthFieldBasedFrameDecoder-解决拆包粘包问题的解码器
    LengthFieldBasedFrameDecoder的构造器参数中包括:maxFrameLength:指定解码器所能处理的数据包的最大长度,超过该长度则抛出TooLongFrameException异常。lengthFieldOffset:指定长度字段的起始位置。lengthFieldLength:指定长度字段的长度。lengthAdjustment:指定长度字段所表示......