在聚合框架C#中使用构面

Adz*_*_12 1 c# mongodb aggregation-framework mongodb-.net-driver

我想在我的数据上创建一个汇总,以获取.Net应用程序中书籍集合的特定标签的总数。

我有以下图书课。

public class Book
{
    public string Id { get; set; }

    public string Name { get; set; }

    [BsonDictionaryOptions(DictionaryRepresentation.Document)]
    public Dictionary<string, string> Tags { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

数据保存后,将以以下格式存储在MongoDB中。

{ 
    "_id" : ObjectId("574325a36fdc967af03766dc"), 
    "Name" : "My First Book", 
    "Tags" : {
        "Edition" : "First", 
        "Type" : "HardBack", 
        "Published" : "2017", 
    }
}
Run Code Online (Sandbox Code Playgroud)

我一直在MongoDB中直接使用构面,并且可以通过使用以下查询来获得所需的结果:

db.{myCollection}.aggregate(
    [
        {
            $match: {
                "Name" : "SearchValue"
            }
        },
        {
            $facet: {
                 "categorizedByTags" : [ 
                     {   
                       $project :
                       { 
                         Tags: { $objectToArray: "$Tags" }
                       }
                     },
                     { $unwind : "$Tags"},
                     { $sortByCount : "$Tags"}
                  ]

            }
        },
    ]
);
Run Code Online (Sandbox Code Playgroud)

但是,我无法将其转移到Mongo的.NET C#驱动程序中。如何使用.NET C#驱动程序执行此操作?

编辑 -我最终将在多面图书清单页面的一部分上查询关于图书其他属性的数据库,例如出版商,作者,页数等...因此,除非有更好的选择,否则应使用$ facet这样的方式?

dni*_*ess 5

我个人不会$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
    }
}])
Run Code Online (Sandbox Code Playgroud)

可以使用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);
Run Code Online (Sandbox Code Playgroud)

这是使用构面的版本:

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);
Run Code Online (Sandbox Code Playgroud)