Как создать свободную агрегацию, используя MongoDB C# Driver 2.0

Я совершенно новичок в MongoDB и использую его в веб-интерфейсе для обслуживания мобильного приложения.

Теперь мне нужно запустить агрегацию и, поскольку я использую C#, я бы хотел сделать это свободно, используя Aggregate команда на коллекцию, которая возвращает мне IAggregateFluent,

Тем не менее, я застрял, и информация, которую я нашел здесь на SO, не помогает мне, поэтому новый вопрос.

Я создал небольшую коллекцию, которая содержит смартфоны с некоторыми базовыми свойствами, и один элемент в коллекции смартфонов выглядит так:

{
    "name" : "LG Nexus 5",
    "description" : "A Nexus 5 device, created by Google.",
    "typenr" : "LG-NEX-5/WHITE",
    "props" : [ 
        {
            "type" : "os",
            "value" : "Android"
        }, 
        {
            "type" : "storage",
            "value" : "8"
        }, 
        {
            "type" : "storage",
            "value" : "16"
        }, 
        {
            "type" : "storage",
            "value" : "32"
        }, 
        {
            "type" : "storage",
            "value" : "64"
        }
    ]
}

Теперь я создал агрегацию в оболочке, которая выглядит следующим образом:

// Get all the amount of filters that are defined.
db.smartphones.aggregate([
    // Unwind the "props".
    { "$unwind" : "$props" },

    // Grouping phase.
    // Group by unique properties, add a count for the amount of articles, and add articles to an element named "articles".
    // We use the function "$addToSet" here to ensure that only unique articles are being added.
    { 
        "$group" : { 
            "_id" : "$props", 
            count : { "$sum" : 1 }, 
            articles: { 
                "$addToSet": { 
                    name: "$name", 
                    description: "$description", 
                    typenr: "$typenr" 
                } x =>
            } 
        } 
    },

    // Sort the results based on the "_id" field.
    { "$sort" : { "_id" : 1 } }
]);

И теперь мне нужно перевести это на C#.

Во-первых, я создаю следующее (обычный код C#, он просто возвращает IMongoCollection<Article>).

var collection = context.ArticleRepository;

Вот модель, которую возвращает коллекция:

public class Article
{
    #region Properties

    /// <summary>
    ///     Unique identifier for the article.
    /// </summary>
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    /// <summary>
    ///     Name of the article.
    /// </summary>
    [BsonElement("name")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString Name { get; set; }

    /// <summary>
    ///     Name of the element but in lowercase.
    /// </summary>
    /// <remarks>
    ///     We'll create this field to enable text-search on this field without respecting capital letters.
    /// </remarks>
    [BsonElement("namelc")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString LowercaseName { get; set; }

    /// <summary>
    ///     Specification of the article.
    /// </summary>
    [BsonElement("specification")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString Specificiation { get; set; }

    /// <summary>
    ///     Brand of the article.
    /// </summary>
    [BsonElement("brand")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString Brand { get; set; }

    /// <summary>
    ///     Supplier of the article.
    /// </summary>
    [BsonElement("supplier")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public Supplier Supplier { get; set; }

    /// <summary>
    ///     Number of the article.
    /// </summary>
    [BsonElement("nr")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString ArticleNumber { get; set; }

    /// <summary>
    ///     Gtin number of the article.
    /// </summary>
    [BsonElement("gtin")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string ArticleGtin { get; set; }

    /// <summary>
    ///     type number of the article.
    /// </summary>
    [BsonElement("typeNr")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string TypeNumber { get; set; }

    /// <summary>
    ///     Properties of the article.
    /// </summary>
    /// <remarks>
    ///     This field can be used to ensure that we can filter on the articles.
    ///     By default, this is an empty list, this avoids initialization logic.
    /// </remarks>
    [BsonElement("props")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public List<ArticleProperty> Properties { get; set; } = new List<ArticleProperty>();

    #endregion
}

/// <summary>
///     Class representing a single supplier in the database.
/// </summary>
/// <remarks>
///     This class is not used as a "root" document inside our database.
///     Instead, it's being embedded into our "Articles" document.
/// </remarks>
public class Supplier
{
    #region Properties

    /// <summary>
    ///     Name of the supplier.
    /// </summary>
    [BsonElement("supplier")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString Name { get; set; }

    /// <summary>
    ///     Gln of the supplier.
    /// </summary>
    [BsonElement("gln")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString Gln { get; set; }

    #endregion
}

/// <summary>
///     Class representing a single property for an article in the database.
/// </summary>
/// <remarks>
///     This class is not used as a "root" document inside our database.
///     Instead, it's being embedded into our "Articles" document.
/// </remarks>
public class ArticleProperty
{
    #region Properties

    /// <summary>
    ///     Type of the property.
    /// </summary>
    [BsonElement("type")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString Type { get; set; }

    /// <summary>
    ///     Value of the property.
    /// </summary>
    [BsonElement("value")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public BsonString Value { get; set; }

    #endregion
}

Теперь мне нужно объединиться в этой коллекции, и я уже борюсь с основами:

// Build the aggregation using the fluent api.
var aggregation = collection.Aggregate()
    .Unwind(x => x.Properties)
    .Group(x => new { x.Properties );

Прямо сейчас я пытаюсь сгруппировать только свойства, как при агрегации, но это приводит к следующей ошибке:

CS0411 The type arguments for method 'IAggregateFluent<BsonDocument>.Group<TNewResult>(ProjectionDefinition<BsonDocument, TNewResult>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Но даже когда это работает, мне также нужны дополнительные свойства, как count а также addToSet, Может ли кто-нибудь помочь мне с этим. Я уже 2 дня ищу это, и это сводит меня с ума.

редактировать

Я обнаружил, что группа, за которой следует раскрутка, работает в C#, но почему она не работает сначала с раскруткой? Мне действительно нужно, чтобы расслабление произошло первым.

Редактировать 2 Мне удалось получить небольшую часть работы, включая group команда. Смотрите код ниже:

var aggregation = collection.Aggregate()
    .Unwind<Smartphone, UnwindedSmartphone>(x => x.Properties)
    .Group(key => key.Property, g => new
    {
        Id = g.Key,
        Count = g.Count()
    });

Однако мне нужно больше информации о том, как передать свойство Articles из команды агрегации.

1 ответ

Решение

Я нашел решение проблемы. Следует использовать следующий код C#:

var aggregation = collection.Aggregate()
    .Unwind<Smartphone, UnwindedSmartphone>(x => x.Properties)
    .Group(key => key.Property, g => new
    {
        Id = g.Key,
        Count = g.Count(),
        Articles = g.Select(x => new
        {
            Name = x.Name
        }).Distinct()
    })
    .SortBy(x => x.Id);

Это дает мне следующую агрегацию:

db.smartphones.aggregate([{ "$unwind" : "$props" }, { "$group" : { "_id" :     "$props", "Count" : { "$sum" : 1 }, "Articles" : { "$addToSet" : { "Name" :     "$name" } } } }, { "$sort" : { "_id" : 1 } }])
Другие вопросы по тегам