[英]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.