简体   繁体   English

如何使用 BsonDocument C# .NET 驱动程序在 MongoDB 中将多个投影和查找作为聚合执行?

[英]How to perform multiple projections and lookups as aggregate in MongoDB using BsonDocument C# .NET driver?

I can't achieve to perform multiple projections and lookups using aggregate functionality with the C# .NET driver.我无法通过 C# .NET 驱动程序使用聚合功能来执行多个投影和查找。

Here the query I need to replicate with mongodb C# .NET driver.这里我需要使用 mongodb C# .NET 驱动程序复制查询。

db.organizations.aggregate([
  {
    "$project": {
      "_id": {
        "$toString": "$_id"
      },
      "Name": "$Name",
      "LastDateUploaded": "$LastDateUploaded",
      "LastDateEvaluated": "$LastDateEvaluated",
      "PriorityId": "$PriorityId"
    }
  },
  {
    "$lookup": {
      "from": "workflows",
      "localField": "_id",
      "foreignField": "Data.OrganizationId",
      "as": "RelatedWorkflows"
    }
  },
  {
    "$lookup": {
      "from": "priorities",
      "localField": "PriorityId",
      "foreignField": "_id",
      "as": "Priority"
    }
  },
  {
    "$unwind": "$Priority"
  },
  {
    "$project": {
      "Name": "$Name",
      "WorkflowCounter": {
        "$size": "$RelatedWorkflows"
      },
      "LastDateUploaded": "$LastDateUploaded",
      "LastDateEvaluated": "$LastDateEvaluated",
      "Priority": "$Priority.Value"
    }
  },
  {
    "$sort": {
      "Priority": -1,
      "WorkflowCounter": 1,
      "LastDateUploaded": -1,
      "LastDateEvaluated": -1
    }
  }
])

I have tried to do something like this:我试图做这样的事情:

public class Organization
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string Id {get; set;}
        public string NPOId { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        [BsonRepresentation(BsonType.ObjectId)]
        public string PriorityId { get; set; }
        [BsonIgnoreIfDefault]
        public Priority Priority { get; set; }
        public string City { get; set; }
        public string County { get; set; }
        [MaxLength(2)]
        public string State { get; set; }
        [BsonRepresentation(BsonType.ObjectId)]
        public string CountryId { get; set; }
        [BsonIgnoreIfDefault]
        public Country Country { get; set; }
        [MaxLength(5)]
        public string Zip { get; set; }
        public string TaxCode { get; set; }
        public string ParentTaxCode { get; set; }
        [BsonRepresentation(BsonType.ObjectId)]
        public string CharityTypeId { get; set; }
        [BsonRepresentation(BsonType.ObjectId)]
        public string PreferredExtractorId { get; set; }
        [BsonIgnoreIfDefault]
        public User PreferredExtractor{ get; set; }
        [BsonIgnoreIfDefault]
        public CharityType CharityType { get; set; }
        public string URL { get; set; }
        public decimal Revenue { get; set; }
        public decimal Expenses { get; set; }
        public decimal Assets { get; set; }
        public decimal Excess { get; set; }
        public string IRSType { get; set; }
        public string ICPAScore { get; set; }
        public string ICPBScore { get; set; }
        public string[] DefaultRules { get; set; }
        [BsonIgnore]
        public long NumberOfWorkflows { get; set; }
        public DateTime? LastDateUploaded { get; set; }
        public DateTime? LastDateEvaluated { get; set; }
    }

var organizations = db.GetCollection<Organization>("catalog.organizations");
            var aggregation = organizations.Aggregate().Match(_ => true);

            var projectionOne = new BsonDocument {
                { "$project", new BsonDocument { { "_id", new BsonDocument { { "$toString", "$_id" } } } } },
                { "Name", "$Name"},
                { "LastDateUploaded", "$LastDateUploaded" },
                { "LastDateEvaluated", "$LastDateEvaluated"},
                { "PriorityId", "$PriorityId"}
            };

            aggregation.Project(projectionOne);

            aggregation.AppendStage<Organizations>(new BsonDocument {
                { "$lookup", new BsonDocument { { "from", "wcf.workflows" }, { "localField", "_id" }, { "foreignField", "Data.OrganizationId" }, { "as", "RelatedWorkflows" } } }
            });

            aggregation.AppendStage<Organizations>(new BsonDocument {
                { "$lookup", new BsonDocument { { "from", "catalog.priorities" }, { "localField", "PriorityId" }, { "foreignField", "_id" }, { "as", "Priority" } } }
            });

            aggregation.AppendStage<Organizations>(new BsonDocument {
                { "$unwind", "$Priority" }
            });

            aggregation.AppendStage<Organizations>(new BsonDocument {
                { "$project", new BsonDocument { { "Name", "$Name" }, { "WorkflowCounter", new BsonDocument { { "$size", "$RelatedWorkflows" } } } } },
                { "LastDateUploaded", "$LastDateUploaded" },
                { "LastDateEvaluated", "$LastDateEvaluated"},
                { "PriorityValue", "$Priority.Value"}
            });

            aggregation.AppendStage<Organizations>(new BsonDocument {
                { "$sort", new BsonDocument { { "Priority", 1 }, { "WorkflowCounter", 1 }, { "LastDateUploaded", -1 }, { "LastDateEvaluated", -1} } }
            });

            var organizationsList = await aggregation.ToListAsync();

However This is not working, for example I inverted the sort options and always is returning the same value.但是这不起作用,例如我反转了排序选项并且总是返回相同的值。 I tried to get the string representation of the mongo query bu I got only我试图获得 mongo 查询的字符串表示,但我只得到

aggregate([{ "$match" : { } }])

and is not appending the aggregate definitions.并且不附加聚合定义。

I tried to use fluent notation to perform the lookups but I need to perform the lookup using an ObjectId and string fields, so for that reason I'm parsing firstly on mongodb side the ObjectId to string with the first projection and seems like there is not equivalence on fluent notation to transform ObjectId into string in order to perform the lookup (aka join).我尝试使用流畅的表示法来执行查找,但我需要使用 ObjectId 和字符串字段来执行查找,因此出于这个原因,我首先在 mongodb 端解析 ObjectId 以使用第一个投影进行字符串处理,似乎没有等价于将 ObjectId 转换为字符串以执行查找(又名连接)的流利符号。

Here the testing proof that the query is working properly on mongo shell: https://mongoplayground.net/p/dKT8uQHjHnd这是查询在 mongo shell 上正常工作的测试证明: https : //mongoplayground.net/p/dKT8uQHjHnd

I expected to get the first document from the list generated like in the mongo playground example, but I always obtain the first element of the collection.我希望从 mongo playground 示例中生成的列表中获取第一个文档,但我总是获取集合的第一个元素。

I ended doing the next:我结束了下一步:

        var organizations = db.GetCollection<Organization>("catalog.organizations");
        var projectionOne = new BsonDocument {
                                                { "$project", new BsonDocument { 
                                                        { "_id", new BsonDocument { { "$toString", "$_id" } } },
                                                        { "Name", "$Name"},
                                                        { "LastDateUploaded", "$LastDateUploaded" },
                                                        { "LastDateEvaluated", "$LastDateEvaluated"},
                                                        { "PriorityId", "$PriorityId"}
                                                    } 
                                                }
        };

        var lookupOne = new BsonDocument {
            { "$lookup", new BsonDocument { { "from", "wfc.workflows" }, { "localField", "_id" }, { "foreignField", "Data.OrganizationId" }, { "as", "RelatedWorkflows" } } }
        };
        var lookupTwo = new BsonDocument {
            { "$lookup", new BsonDocument { { "from", "catalog.priorities" }, { "localField", "PriorityId" }, { "foreignField", "_id" }, { "as", "Priority" } } }
        };
        var unwindTwo = new BsonDocument {
            { "$unwind", "$Priority" }
        };

        var projectionTwo = new BsonDocument {
                                            { "$project", new BsonDocument { 
                                                    { "Name", "$Name" }, 
                                                    { "WorkflowCounter", new BsonDocument { { "$size", "$RelatedWorkflows" } } },
                                                    { "LastDateUploaded", "$LastDateUploaded" },
                                                    { "LastDateEvaluated", "$LastDateEvaluated"},
                                                    { "PriorityValue", "$Priority.Value"}
                                                } 
                                            }
        };

        var sort = new BsonDocument {
            { "$sort", new BsonDocument { { "PriorityValue", -1 }, { "WorkflowCounter", 1 }, { "LastDateUploaded", -1 }, { "LastDateEvaluated", -1} } }
        };

        var aggregation = organizations.Aggregate<OrganizationWithWorkflows>(new [] {projectionOne, lookupOne, lookupTwo, unwindTwo, projectionTwo, sort});

        var organizationsList = await aggregation.ToListAsync();

And I created this class to get the last projection results:我创建了这个类来获取最后的投影结果:

 [BsonIgnoreExtraElements]
 public class OrganizationWithWorkflows
 {
      public string Id { get; set; }
      public string Name { get; set; }
      public long WorkflowCounter {get; set;}
      public DateTime? LastDateUploaded { get; set; }
      public DateTime? LastDateEvaluated { get; set; }
      public int PriorityValue { get; set; }
 }

It took me a while but I finally resolved my challenge here, which in part was performing a lookup using ObjectId and string fields applying a cast from ObjectId to string and within the same query applying multiple projections and multiple lookups.我花了一段时间,但我终于在这里解决了我的挑战,部分是使用 ObjectId 和字符串字段执行查找,应用从 ObjectId 到字符串的强制转换,并在同一查询中应用多个投影和多个查找。

Please notice that the field counter is the size of the elements contained in the resultant array of RelatedWorkflows , but this can be done as well applying an unwind after the lookupOne and grouping to get the counter value with expression { $sum ,1 } but on my case it was enough to use the $size expression from the mentioned array.请注意,字段 counter 是包含在结果数组RelatedWorkflows中的元素的大小,但这也可以在 lookupOne 和分组后应用展开以使用表达式{ $sum ,1 }但在在我的情况下,使用上述数组中的 $size 表达式就足够了。

I hope this can help to all those who are having little troubles understanding how to work with MongoDB Aggregation and C# .NET Driver using BsonDocuments as this query was not possible to be created using fluent notation because of the conversion of the ObjectId into string and use that one for lookupOne, maybe I'm wrong with this last part, so if you know how to do it, believe I will be glad to learn it as well.我希望这可以帮助所有那些在理解如何使用BsonDocuments使用 MongoDB 聚合和 C# .NET 驱动程序时遇到一些麻烦的人,因为无法使用流畅的表示法创建此查询,因为将 ObjectId 转换为字符串并使用那个用于 lookupOne 的,也许我在最后一部分上错了,所以如果你知道怎么做,相信我也会很高兴学习它。

In order to get my solution I found this awesome post from Mikael Koskinen and reading the mongodb documentation to use expression $toString为了获得我的解决方案,我从 Mikael Koskinen 找到了这篇很棒的帖子,并阅读了 mongodb 文档以使用表达式$toString

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 Mongodb C# 驱动程序检查 BsonDocument 中是否存在密钥? - How to check if key exists in BsonDocument or not using Mongodb C# driver? MongoDB C#驱动程序IAsyncCursor <BsonDocument> 行为? - MongoDB C# driver IAsyncCursor<BsonDocument> behavior? MongoDB - 使用 .NET 驱动程序和 LINQ 进行多次查找(带分组和过滤) - MongoDB - multiple lookups using .NET driver and LINQ (with grouping and filtering) 如何使用 MongoDB C# 驱动程序投影查询嵌套列表 - How to query nested list with MongoDB C# Driver projections 如何使用 MongoDB C# 驱动程序聚合 $lookup? - How to aggregate $lookup with MongoDB C# driver? 如何使用C#驱动程序在MongoDB上执行$ setIsSubset? - How to perform a $setIsSubset on MongoDB using C# driver? 查询 MongoDB C#:如何在 BsonDocument 中提取调用聚合方法产生的字段? - Query MongoDB C#: how can I extract in a BsonDocument the field that results from calling aggregate method? 使用mongodb C#驱动程序选择一个BsonDocument及其数组仅包含最后N个元素 - Selecting a BsonDocument with its array containing only last N elements using mongodb C# driver 如何在C#mongodb中查询BsonDocument - How to query on a BsonDocument in C# mongodb 如何使用官方 MongoDB C# 驱动程序将 BsonDocument 转换为强类型对象? - How to convert a BsonDocument into a strongly typed object with the official MongoDB C# driver?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM