使用 C# 聚合 $lookup

2024-01-24

我有以下 MongoDb 查询正在运行:

db.Entity.aggregate(
    [
        {
            "$match":{"Id": "12345"}
        },
        {
            "$lookup": {
                "from": "OtherCollection",
                "localField": "otherCollectionId",
                "foreignField": "Id",
                "as": "ent"
            }
        },
        { 
            "$project": { 
                "Name": 1,
                "Date": 1,
                "OtherObject": { "$arrayElemAt": [ "$ent", 0 ] } 
            }
        },
        { 
            "$sort": { 
                "OtherObject.Profile.Name": 1
            } 
        }
    ]
)

这会检索与另一个集合中的匹配对象连接的对象列表。

有谁知道我如何在 C# 中使用 LINQ 或使用这个确切的字符串来使用它?

我尝试使用以下代码,但似乎找不到类型QueryDocument and MongoCursor- 我认为它们已被弃用?

BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{ name : value }");
QueryDocument queryDoc = new QueryDocument(document);
MongoCursor toReturn = _connectionCollection.Find(queryDoc);

无需解析 JSON。这里的一切实际上都可以直接使用 LINQ 或 Aggregate Fluent 接口来完成。

只是使用一些演示课程,因为这个问题并没有真正提供太多内容。

Setup

基本上我们这里有两个集合,分别是

entities

{ "_id" : ObjectId("5b08ceb40a8a7614c70a5710"), "name" : "A" }
{ "_id" : ObjectId("5b08ceb40a8a7614c70a5711"), "name" : "B" }

and others

{
        "_id" : ObjectId("5b08cef10a8a7614c70a5712"),
        "entity" : ObjectId("5b08ceb40a8a7614c70a5710"),
        "name" : "Sub-A"
}
{
        "_id" : ObjectId("5b08cefd0a8a7614c70a5713"),
        "entity" : ObjectId("5b08ceb40a8a7614c70a5711"),
        "name" : "Sub-B"
}

还有几个将它们绑定到的类,就像非常基本的示例一样:

public class Entity
{
  public ObjectId id;
  public string name { get; set; }
}

public class Other
{
  public ObjectId id;
  public ObjectId entity { get; set; }
  public string name { get; set; }
}

public class EntityWithOthers
{
  public ObjectId id;
  public string name { get; set; }
  public IEnumerable<Other> others;
}

 public class EntityWithOther
{
  public ObjectId id;
  public string name { get; set; }
  public Other others;
}

Queries

流畅的界面

var listNames = new[] { "A", "B" };

var query = entities.Aggregate()
    .Match(p => listNames.Contains(p.name))
    .Lookup(
      foreignCollection: others,
      localField: e => e.id,
      foreignField: f => f.entity,
      @as: (EntityWithOthers eo) => eo.others
    )
    .Project(p => new { p.id, p.name, other = p.others.First() } )
    .Sort(new BsonDocument("other.name",-1))
    .ToList();

请求发送到服务器:

[
  { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
  { "$lookup" : { 
    "from" : "others",
    "localField" : "_id",
    "foreignField" : "entity",
    "as" : "others"
  } }, 
  { "$project" : { 
    "id" : "$_id",
    "name" : "$name",
    "other" : { "$arrayElemAt" : [ "$others", 0 ] },
    "_id" : 0
  } },
  { "$sort" : { "other.name" : -1 } }
]

可能是最容易理解的,因为 Fluent 接口与通用 BSON 结构基本相同。这$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/阶段有所有相同的论点,并且$arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/表示为First()。为了$sort https://docs.mongodb.com/manual/reference/operator/aggregation/sort/您只需提供 BSON 文档或其他有效表达式即可。

另一种是更新的表达形式$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/带有 MongoDB 3.6 及更高版本的子管道语句。

BsonArray subpipeline = new BsonArray();

subpipeline.Add(
  new BsonDocument("$match",new BsonDocument(
    "$expr", new BsonDocument(
      "$eq", new BsonArray { "$$entity", "$entity" }  
    )
  ))
);

var lookup = new BsonDocument("$lookup",
  new BsonDocument("from", "others")
    .Add("let", new BsonDocument("entity", "$_id"))
    .Add("pipeline", subpipeline)
    .Add("as","others")
);

var query = entities.Aggregate()
  .Match(p => listNames.Contains(p.name))
  .AppendStage<EntityWithOthers>(lookup)
  .Unwind<EntityWithOthers, EntityWithOther>(p => p.others)
  .SortByDescending(p => p.others.name)
  .ToList();

请求发送到服务器:

[ 
  { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
  { "$lookup" : {
    "from" : "others",
    "let" : { "entity" : "$_id" },
    "pipeline" : [
      { "$match" : { "$expr" : { "$eq" : [ "$$entity", "$entity" ] } } }
    ],
    "as" : "others"
  } },
  { "$unwind" : "$others" },
  { "$sort" : { "others.name" : -1 } }
]

Fluent“Builder”尚不直接支持语法,LINQ 表达式也不支持$expr https://docs.mongodb.com/manual/reference/operator/query/expr/运算符,但是您仍然可以使用BsonDocument and BsonArray或其他有效的表达方式。在这里我们还“输入”$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/结果以便应用$sort https://docs.mongodb.com/manual/reference/operator/aggregation/sort/使用表达式而不是BsonDocument如前所示。

除了其他用途之外,“子管道”的主要任务是减少目标数组中返回的文档$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/。还有$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/这里的目的实际上是被“合并” https://docs.mongodb.com/manual/core/aggregation-pipeline-optimization/#lookup-unwind-coalescence进入$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/服务器执行上的语句,因此这通常比仅获取结果数组的第一个元素更有效。

可查询的群组加入

var query = entities.AsQueryable()
    .Where(p => listNames.Contains(p.name))
    .GroupJoin(
      others.AsQueryable(),
      p => p.id,
      o => o.entity,
      (p, o) => new { p.id, p.name, other = o.First() }
    )
    .OrderByDescending(p => p.other.name);

请求发送到服务器:

[ 
  { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
  { "$lookup" : {
    "from" : "others",
    "localField" : "_id",
    "foreignField" : "entity",
    "as" : "o"
  } },
  { "$project" : {
    "id" : "$_id",
    "name" : "$name",
    "other" : { "$arrayElemAt" : [ "$o", 0 ] },
    "_id" : 0
  } },
  { "$sort" : { "other.name" : -1 } }
]

这几乎是相同的,但只是使用不同的接口并产生略有不同的 BSON 语句,实际上只是因为功能语句中的简化命名。这确实带来了另一种可能性,即简单地使用$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/生产自SelectMany():

var query = entities.AsQueryable()
  .Where(p => listNames.Contains(p.name))
  .GroupJoin(
    others.AsQueryable(),
    p => p.id,
    o => o.entity,
    (p, o) => new { p.id, p.name, other = o }
  )
  .SelectMany(p => p.other, (p, other) => new { p.id, p.name, other })
  .OrderByDescending(p => p.other.name);

请求发送到服务器:

[
  { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
  { "$lookup" : {
    "from" : "others",
    "localField" : "_id",
    "foreignField" : "entity",
    "as" : "o"
  }},
  { "$project" : {
    "id" : "$_id",
    "name" : "$name",
    "other" : "$o",
    "_id" : 0
  } },
  { "$unwind" : "$other" },
  { "$project" : {
    "id" : "$id",
    "name" : "$name",
    "other" : "$other",
    "_id" : 0
  }},
  { "$sort" : { "other.name" : -1 } }
]

通常放置一个$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/直接跟随$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/实际上是一个“优化模式” https://docs.mongodb.com/manual/core/aggregation-pipeline-optimization/#lookup-unwind-coalescence为聚合框架。然而,.NET 驱动程序确实通过强制$project在两者之间而不是使用隐含的命名"as"。如果不是因为这个,这实际上比$arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/当您知道您有“一个”相关结果时。如果你想要$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/“合并”,那么您最好使用流畅的界面,或稍后演示的不同形式。

可质疑的自然

var query = from p in entities.AsQueryable()
            where listNames.Contains(p.name) 
            join o in others.AsQueryable() on p.id equals o.entity into joined
            select new { p.id, p.name, other = joined.First() }
            into p
            orderby p.other.name descending
            select p;

请求发送到服务器:

[
  { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
  { "$lookup" : {
    "from" : "others",
    "localField" : "_id",
    "foreignField" : "entity",
    "as" : "joined"
  } },
  { "$project" : {
    "id" : "$_id",
    "name" : "$name",
    "other" : { "$arrayElemAt" : [ "$joined", 0 ] },
    "_id" : 0
  } },
  { "$sort" : { "other.name" : -1 } }
]

一切都非常熟悉,而且实际上只是功能性命名。就像使用$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/ option:

var query = from p in entities.AsQueryable()
            where listNames.Contains(p.name) 
            join o in others.AsQueryable() on p.id equals o.entity into joined
            from sub_o in joined.DefaultIfEmpty()
            select new { p.id, p.name, other = sub_o }
            into p
            orderby p.other.name descending
            select p;

请求发送到服务器:

[ 
  { "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
  { "$lookup" : {
    "from" : "others",
    "localField" : "_id",
    "foreignField" : "entity",
    "as" : "joined"
  } },
  { "$unwind" : { 
    "path" : "$joined", "preserveNullAndEmptyArrays" : true
  } }, 
  { "$project" : { 
    "id" : "$_id",
    "name" : "$name",
    "other" : "$joined",
    "_id" : 0
  } }, 
  { "$sort" : { "other.name" : -1 } }
]

实际上正在使用“优化合并” https://docs.mongodb.com/manual/core/aggregation-pipeline-optimization/#lookup-unwind-coalescence形式。译者仍然坚持添加一个$project https://docs.mongodb.com/manual/reference/operator/aggregation/project/因为我们需要中间select以使该声明有效。

Summary

因此,有很多方法可以本质上得到具有完全相同结果的基本相同的查询语句。虽然您“可以”将 JSON 解析为BsonDocument形成并将其提供给流利的Aggregate()命令,通常最好使用自然构建器或 LINQ 接口,因为它们可以轻松映射到同一语句。

选项与$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/很大程度上显示,因为即使使用“单一”匹配,“合并”形式实际上也比使用更优化$arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/获取“第一个”数组元素。考虑到诸如 BSON 限制之类的事情,这一点甚至变得更加重要,其中$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/目标数组可能会导致父文档超过 16MB,而无需进一步过滤。这里还有另一篇文章聚合 $lookup 匹配管道中文档的总大小超过最大文档大小 https://stackoverflow.com/a/45726501/2313887我实际上讨论了如何通过使用此类选项或其他选项来避免达到该限制Lookup()目前仅适用于流畅界面的语法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C# 聚合 $lookup 的相关文章

  • C# SmtpClient编程中如何设置带有中文的附件文件名?

    我的代码如下 ContentType ct new ContentType ct MediaType MediaTypeNames Application Octet ct Name 这是一个很长的中文文件名希望能用它在附件名中 Doc A
  • 如何使用 openSSL 函数验证 PEM 证书的密钥长度

    如何验证以这种方式生成的 PEM 证书的密钥长度 openssl genrsa des3 out server key 1024 openssl req new key server key out server csr cp server
  • EntityHydrate 任务失败

    我最近安装了 Visual Studio 11 Beta 和 Visual Studio 2010 之后 我无法在 Visual Studio 2010 中构建依赖于 PostSharp 的项目 因此我卸载了 Visual Studio 1
  • 在 C 语言中,为什么数组的地址等于它的值?

    在下面的代码中 指针值和指针地址与预期不同 但数组值和地址则不然 怎么会这样 Output my array 0022FF00 my array 0022FF00 pointer to array 0022FF00 pointer to a
  • 防止控制台应用程序中的内存工作集最小化?

    我想防止控制台应用程序中的内存工作集最小化 在Windows应用程序中 我可以这样做覆盖 SC MINIMIZE 消息 http support microsoft com kb 293215 en us fr 1 但是 如何在控制台应用程
  • Android NDK 代码中的 SIGILL

    我在市场上有一个 NDK 应用程序 并获得了有关以下内容的本机崩溃报告 SIGILL信号 我使用 Google Breakpad 生成本机崩溃报告 以下是详细信息 我的应用程序是为armeabi v7a with霓虹灯支持 它在 NVIDI
  • Makefile 和 .Mak 文件 + CodeBlocks 和 VStudio

    我对整个 makefile 概念有点陌生 所以我对此有一些疑问 我正在 Linux 中使用 CodeBlocks 创建一个项目 我使用一个名为 cbp2mak 的工具从 CodeBlocks 项目创建一个 make 文件 如果有人知道更好的
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • JavaScript 错误:MVC2 视图中的条件编译已关闭

    我试图在 MVC2 视图页面中单击时调用 JavaScript 函数 a href Select a JavaScript 函数 function SelectBenefit id code alert id alert code 这里 b
  • 测量进程消耗的 CPU 时钟

    我用 C 语言编写了一个程序 它是作为研究结果创建的程序 我想计算程序消耗的确切 CPU 周期 精确的循环次数 知道我怎样才能找到它吗 The valgrind tool cachegrind valgrind tool cachegrin
  • 在 azure blob 存储中就地创建 zip 文件

    我将文件存储在 Blob 存储帐户内的一个容器中 我需要在第二个容器中创建一个 zip 文件 其中包含第一个容器中的文件 我有一个使用辅助角色和 DotNetZip 工作的解决方案 但由于 zip 文件的大小最终可能达到 1GB 我担心在进
  • 猫鼬中的数组过滤器

    将查询转换为节点 arrayfilter 在 mongoose 中工作的版本或者如何在节点应用程序中运行它们 db getCollection student update id ObjectId 5a377d62d21a3025a3c3a
  • .NET 和 Mono 之间的开发差异

    我正在研究 Mono 和 NET C 将来当项目开发时我们需要在 Linux 服务器上运行代码 此时我一直在研究 ASP NET MVC 和 Mono 我运行 Ubuntu 发行版 想要开发 Web 应用程序 其他一些开发人员使用 Wind
  • 以编程方式创建 Blob 存储容器

    我有一个要求 即在创建公司时 在我的 storageaccount 中创建关联的 blob 存储容器 并将容器名称设置为传入的字符串变量 我已尝试以下操作 public void AddCompanyStorage string subDo
  • 如何编写一个接受 int 或 float 的 C 函数?

    我想用 C 语言创建一个扩展 Python 的函数 该函数可以接受 float 或 int 类型的输入 所以基本上 我想要f 5 and f 5 5 成为可接受的输入 我认为我不能使用if PyArg ParseTuple args i v
  • 如何从 Windows Phone 7 模拟器获取数据

    我有一个 WP7 的单元测试框架 它在手机上运行 结果相当难以阅读 因此我将它们写入 XDocument 我的问题是 如何才能将这个 XML 文件从手机上移到我的桌面上 以便我可以实际分析结果 到目前为止 我所做的是将 Debugger B
  • 如何组合两个 lambda [重复]

    这个问题在这里已经有答案了 可能的重复 在 C 中组合两个 lambda 表达式 https stackoverflow com questions 1717444 combining two lamba expressions in c
  • 如果将变量设置为等于新对象,旧对象会发生什么?

    假设我们有一个 X 类not有一个超载的operator 功能 class X int n X n 0 X int n n n int main X a 1 an object gets constructed here more code
  • 从后面的代码添加外部 css 文件

    我有一个 CSS 文件 例如 SomeStyle css 我是否可以将此样式表文档从其代码隐藏应用到 aspx 页面 您可以将文字控件添加到标头控件中 Page Header Controls Add new System Web UI L
  • 如何在 C# 中获取 CMD/控制台编码

    我需要指定正确的代码页来使用 zip 库打包文件 正如我所见 我需要指定控制台编码 在我的例子中为 866 C Users User gt mode Status for device CON Lines 300 Columns 130 K

随机推荐

  • VBA用公式填充多张纸上的单元格

    我正在尝试为工作簿的每张工作表中的每个单元格设置公式 我需要将 2 个公式分布在 2 个不同的单元格范围内 我在 Variant 中定义了 strFormula 1 和 2 对于公式1 我希望分配到A到AJ列下的单元格 对于公式 2 我希望
  • 改变时间轴刻度标签的字体大小

    我正在根据常规时间轴绘制时间序列数据 目前 我使用默认的 多刻度 刻度格式 因此我在 X 轴上看到日期与 AM PM 小时的组合 现在 如何以更大的字体显示日期 使它们从小时刻度中脱颖而出 所有刻度似乎都有相同的 刻度 CSS 类 所以我无
  • R部分字符串匹配和返回值(在R中)

    我有多个采购数据库 我需要在其中运行我构建的 关键字 列表来识别某些产品 如果有匹配 我想将产品标记到手术类别 这是一个例子 采购数据库 实际上我有超过2 000 000行要查看 d lt data frame prod desc c BA
  • XCode 全局断点不显示堆栈跟踪

    我从 libobjc A dylib 和 CoreFoundation 位置设置了全局断点 我运行我的 iPhone 应用程序 它遇到了异常 XCode 在断点处停止 但在日志中没有显示任何错误 待处理断点 1 objc exception
  • java aes javax.crypto.BadPaddingException:给定的最终块未正确填充

    public class AES public String getEncrypt String pass String password encrypt pass return password public String getDecr
  • WSO2 API Manager 网关集群。如何在 api-manager.xml 中设置网关端点

    我计划在我的公司使用 WSO2 API 管理器 因此尝试使其能够集群工作 它由 Keymanager Gateway manager worker Publisher 2 个 AWS 实例上的 Store 组成 Host1包含Keymana
  • 切换无状态反应组件数组的可见性

    我试图简单地映射从 api 返回的一些数据 并为每个返回的对象创建一个无状态组件 我希望能够单击任何组件来切换其其余数据的可见性 我尝试了多种方法来做到这一点 但一直碰壁 我还搜索了堆栈溢出 但似乎找不到答案 我已经通过使它们成为单独的类组
  • 从 MySQL 中的分层数据生成基于深度的树(无 CTE)

    嗨 很多天我一直在 MySQL 中解决这个问题 但是我无法弄清楚 你们有什么建议吗 基本上 我有一个类别表 其中包含以下域 id name 类别名称 以及parent 类别的父类别的 ID 示例数据 1 Fruit 0 2 Apple 1
  • GAE python:如何使用delete_serving_url

    首先我将图像存储 import cloudstorage as gcs path bucket folder image jpg with gcs open path w as f f write data 然后我得到服务网址 url im
  • 如何动态调整导航栏中的标题大小

    我有一些视图显示在导航控制器中 其中两个视图的导航栏标题较长 问题是 当标题太长而无法容纳时 某些字符会被截断并添加 有什么方法可以告诉导航栏自动调整标题文本的大小以适应 在 ViewDidload 中使用以下代码 目标C self tit
  • 如何使用 2.01 的功能,同时仍然通过一个 apk 支持 1.5?

    我希望我的 Activity 使用 2 01 的某些功能 但我需要它能够在 1 5 设备上运行 据我所知 1 5 设备将无法运行 2 01 功能 但这很好 但我仍然希望他们能够使用其余的活动 我使用 Eclipse 作为 IDE 如何正确设
  • mysql中如何选择一段时间?

    我想做一段时间的MySql选择 但我不知道如何正确地制作它 这就是我尝试过的 SELECT FROM rapoarte WHERE DATE ziua BETWEEN 2010 01 12 AND 2011 01 14 你能帮忙吗 谢谢 塞
  • 数据声明的类型类约束

    显然 在数据声明上放置类型类约束是一个坏主意 src https stackoverflow com questions 2354707 in haskell is there num a infinity a rq 1 comment23
  • 如何编写爬虫?

    我曾想过尝试编写一个简单的爬虫程序 它可以爬行并为我们的 NPO 网站和内容生成其发现结果列表 有人对如何做到这一点有任何想法吗 您将爬虫指向何处开始 它如何发回其发现并仍然继续爬行 它如何知道它发现了什么等等 可以肯定的是 你将重新发明轮
  • 透明操作栏下方的导航抽屉

    我通过使用 GunnarKarlsson 在此处显示的以下代码获得透明的操作栏 透明操作栏 自定义选项卡颜色 https stackoverflow com questions 13726214 transparent actionbar
  • Spring Oauth2 中的 CORS 错误

    我正在使用 Spring 安全性和 Oauth2 但是我是Spring Oauth2的新手 当前端访问资源时 我遇到了CORS错误 我使用以下过滤器来允许其他域访问该资源 Component Order Integer MAX VALUE
  • 如何在类型已实现 Display 的特征对象上实现 Display

    我有一些代码返回类型的特征对象MyTrait这样它就可以返回几个不同的结构之一 我想实施Display特征对象的特征 以便我可以打印该对象 并将详细信息委托给各种结构 因为它们每个都需要自己的自定义格式化程序 我可以通过将格式化方法作为其中
  • 如何通过 JavaFX 显示来自 MYSQL 的阿拉伯语查询搜索?

    SELECT FROM employee WHERE name LIKE 上面的查询工作正常 并通过 phpmyAdmin 查询找到该元素 但在 JavaFX 中使用它却找不到它 并进行英语搜索 那么我需要在java中添加什么才能允许我用阿
  • 哪些语言支持*递归*函数文字/匿名函数?

    看来主流语言都支持函数字面量 http en wikipedia org wiki First class function这些日子 他们也被称为匿名函数 http en wikipedia org wiki Anonymous funct
  • 使用 C# 聚合 $lookup

    我有以下 MongoDb 查询正在运行 db Entity aggregate match Id 12345 lookup from OtherCollection localField otherCollectionId foreignF