在聚合框架 C# 中使用 Facets
Using Facets in the Aggregation Framework C#
我想对我的数据创建一个聚合,以获取我的 .Net 应用程序中书籍集合的特定标签的总计数。
我有以下书籍 class。
public class Book
{
public string Id { get; set; }
public string Name { get; set; }
[BsonDictionaryOptions(DictionaryRepresentation.Document)]
public Dictionary<string, string> Tags { get; set; }
}
并且在保存数据的时候,在MongoDB中以如下格式存储。
{
"_id" : ObjectId("574325a36fdc967af03766dc"),
"Name" : "My First Book",
"Tags" : {
"Edition" : "First",
"Type" : "HardBack",
"Published" : "2017",
}
}
我一直在 MongoDB 中直接使用构面,我能够通过使用以下查询获得我需要的结果:
db.{myCollection}.aggregate(
[
{
$match: {
"Name" : "SearchValue"
}
},
{
$facet: {
"categorizedByTags" : [
{
$project :
{
Tags: { $objectToArray: "$Tags" }
}
},
{ $unwind : "$Tags"},
{ $sortByCount : "$Tags"}
]
}
},
]
);
但是我无法将其传输到 Mongo 的 .NET C# 驱动程序。我如何使用 .NET C# 驱动程序执行此操作?
Edit - 我最终会在数据库中查询书籍的其他属性,作为分面书籍列表页面的一部分,例如出版商、作者、页数等...因此使用 $facet,除非有更好的方法吗?
我个人不会在这里使用 $facet
,因为你只有一个管道,这首先违背了 $facet
的目的...
以下内容更简单且可扩展性更好($facet
将创建一个可能庞大的文档)。
db.collection.aggregate([
{
$match: {
"Name" : "My First Book"
}
}, {
$project: {
"Tags": {
$objectToArray: "$Tags"
}
}
}, {
$unwind: "$Tags"
}, {
$sortByCount: "$Tags"
}, {
$group: { // not really needed unless you need to have all results in one single document
"_id": null,
"categorizedByTags": {
$push: "$$ROOT"
}
}
}, {
$project: { // not really needed, either: remove _id field
"_id": 0
}
}])
这可以使用 C# 驱动程序编写如下:
var collection = new MongoClient().GetDatabase("test").GetCollection<Book>("test");
var pipeline = collection.Aggregate()
.Match(b => b.Name == "My First Book")
.Project("{Tags: { $objectToArray: \"$Tags\" }}")
.Unwind("Tags")
.SortByCount<BsonDocument>("$Tags");
var output = pipeline.ToList().ToJson(new JsonWriterSettings {Indent = true});
Console.WriteLine(output);
这是使用分面的版本:
var collection = new MongoClient().GetDatabase("test").GetCollection<Book>("test");
var project = PipelineStageDefinitionBuilder.Project<Book, BsonDocument>("{Tags: { $objectToArray: \"$Tags\" }}");
var unwind = PipelineStageDefinitionBuilder.Unwind<BsonDocument, BsonDocument>("Tags");
var sortByCount = PipelineStageDefinitionBuilder.SortByCount<BsonDocument, BsonDocument>("$Tags");
var pipeline = PipelineDefinition<Book, AggregateSortByCountResult<BsonDocument>>.Create(new IPipelineStageDefinition[] { project, unwind, sortByCount });
// string based alternative version
//var pipeline = PipelineDefinition<Book, BsonDocument>.Create(
// "{ $project :{ Tags: { $objectToArray: \"$Tags\" } } }",
// "{ $unwind : \"$Tags\" }",
// "{ $sortByCount : \"$Tags\" }");
var facetPipeline = AggregateFacet.Create("categorizedByTags", pipeline);
var aggregation = collection.Aggregate().Match(b => b.Name == "My First Book").Facet(facetPipeline);
var output = aggregation.Single().Facets.ToJson(new JsonWriterSettings { Indent = true });
Console.WriteLine(output);
我想对我的数据创建一个聚合,以获取我的 .Net 应用程序中书籍集合的特定标签的总计数。
我有以下书籍 class。
public class Book
{
public string Id { get; set; }
public string Name { get; set; }
[BsonDictionaryOptions(DictionaryRepresentation.Document)]
public Dictionary<string, string> Tags { get; set; }
}
并且在保存数据的时候,在MongoDB中以如下格式存储。
{
"_id" : ObjectId("574325a36fdc967af03766dc"),
"Name" : "My First Book",
"Tags" : {
"Edition" : "First",
"Type" : "HardBack",
"Published" : "2017",
}
}
我一直在 MongoDB 中直接使用构面,我能够通过使用以下查询获得我需要的结果:
db.{myCollection}.aggregate(
[
{
$match: {
"Name" : "SearchValue"
}
},
{
$facet: {
"categorizedByTags" : [
{
$project :
{
Tags: { $objectToArray: "$Tags" }
}
},
{ $unwind : "$Tags"},
{ $sortByCount : "$Tags"}
]
}
},
]
);
但是我无法将其传输到 Mongo 的 .NET C# 驱动程序。我如何使用 .NET C# 驱动程序执行此操作?
Edit - 我最终会在数据库中查询书籍的其他属性,作为分面书籍列表页面的一部分,例如出版商、作者、页数等...因此使用 $facet,除非有更好的方法吗?
我个人不会在这里使用 $facet
,因为你只有一个管道,这首先违背了 $facet
的目的...
以下内容更简单且可扩展性更好($facet
将创建一个可能庞大的文档)。
db.collection.aggregate([
{
$match: {
"Name" : "My First Book"
}
}, {
$project: {
"Tags": {
$objectToArray: "$Tags"
}
}
}, {
$unwind: "$Tags"
}, {
$sortByCount: "$Tags"
}, {
$group: { // not really needed unless you need to have all results in one single document
"_id": null,
"categorizedByTags": {
$push: "$$ROOT"
}
}
}, {
$project: { // not really needed, either: remove _id field
"_id": 0
}
}])
这可以使用 C# 驱动程序编写如下:
var collection = new MongoClient().GetDatabase("test").GetCollection<Book>("test");
var pipeline = collection.Aggregate()
.Match(b => b.Name == "My First Book")
.Project("{Tags: { $objectToArray: \"$Tags\" }}")
.Unwind("Tags")
.SortByCount<BsonDocument>("$Tags");
var output = pipeline.ToList().ToJson(new JsonWriterSettings {Indent = true});
Console.WriteLine(output);
这是使用分面的版本:
var collection = new MongoClient().GetDatabase("test").GetCollection<Book>("test");
var project = PipelineStageDefinitionBuilder.Project<Book, BsonDocument>("{Tags: { $objectToArray: \"$Tags\" }}");
var unwind = PipelineStageDefinitionBuilder.Unwind<BsonDocument, BsonDocument>("Tags");
var sortByCount = PipelineStageDefinitionBuilder.SortByCount<BsonDocument, BsonDocument>("$Tags");
var pipeline = PipelineDefinition<Book, AggregateSortByCountResult<BsonDocument>>.Create(new IPipelineStageDefinition[] { project, unwind, sortByCount });
// string based alternative version
//var pipeline = PipelineDefinition<Book, BsonDocument>.Create(
// "{ $project :{ Tags: { $objectToArray: \"$Tags\" } } }",
// "{ $unwind : \"$Tags\" }",
// "{ $sortByCount : \"$Tags\" }");
var facetPipeline = AggregateFacet.Create("categorizedByTags", pipeline);
var aggregation = collection.Aggregate().Match(b => b.Name == "My First Book").Facet(facetPipeline);
var output = aggregation.Single().Facets.ToJson(new JsonWriterSettings { Indent = true });
Console.WriteLine(output);