【问题标题】:Aggregation in C# does return null for some properties with MongoDB C# Driver 2.0对于 MongoDB C# Driver 2.0 的某些属性,C# 中的聚合确实返回 null
【发布时间】:2015-08-20 07:33:50
【问题描述】:

我正在编写一个 MongoDB 应用程序,并在 C# fow 复杂查询中使用聚合管道。 当我在 shell 中复制 C# 生成的聚合时,一切似乎都很好。但是,当在 C# 中执行聚合时,某些属性被设置为 null。请参阅下文了解更多信息。

首先,让我展示一下我的模型:

public class Smartphone
{
    #region Properties

    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    [BsonElement("name")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Name { get; set; }

    [BsonElement("description")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Description { get; set; }

    [BsonElement("typenr")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Type { get; set; }

    [BsonElement("props")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public List<SmartphoneProperty> Properties { get; set; }

    #endregion
}

public class UnwindedSmartphone
{
    #region Properties

    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    [BsonElement("name")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Name { get; set; }

    [BsonElement("description")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Description { get; set; }

    [BsonElement("typenr")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Type { get; set; }

    [BsonElement("props")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public SmartphoneProperty Property { get; set; }

    #endregion
}

public class SmartphoneProperty
{
    #region Properties

    [BsonElement("type")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Type { get; set; }

    [BsonElement("value")]
    [BsonIgnoreIfNull]
    [BsonIgnoreIfDefault]
    public string Value { get; set; }

    #endregion
}

我的集合中的单个文档确实如下所示:

{
    "_id" : ObjectId("55d45c0285afc59c146f66f0"),
    "name" : "LG Nexus 6",
    "description" : "A Nexus 6 device, created by Google.",
    "typenr" : "LG-NEX-5/BLACK",
    "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" 
                } 
            } 
        } 
    },

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

此聚合的单个结果返回以下内容:

"_id" : {
    "type" : "storage",
    "value" : "128"
},
"count" : 1.0000000000000000,
"articles" : [ 
    {
        "name" : "Apple iPhone 6",
        "description" : "An iPhone 6 device, created by Apple.",
        "typenr" : "APP-IPHONE-6/BLACK"
    }
]

现在,在 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,
            description = x.Description,
            typenr = x.Type
        }).Distinct()
    })
    .SortBy(x => x.Id);

如果我检查此聚合转换为的命令,它似乎如下:

// 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" 
                } 
            } 
        } 
    }, 
    { "$sort" : { "_id" : 1 } }
])

所以,它与我尝试转换为 C# 代码的原始聚合相同,只是属性用双引号括起来,但这不是问题。

如果我在 shell 中执行这个聚合,结果很好。 但是,当它在 C# 中执行时,articles 属性对于namedescriptiontypenr 具有null 值。

有谁知道为什么会这样?

【问题讨论】:

  • 感谢您的回答,但是应该将它们更改为我的代码,因为它不是很清楚。我没有看到我需要在哪里指定输出类型。
  • 好的,所以正要在“它像这样序列化”上调用“phooey”,但显然你刚刚发现你需要给它一个类来使用 lambda 进行迭代。

标签: c# mongodb mongodb-query


【解决方案1】:

好的,

感谢@BlakesSeven 为我指明了正确的方向(请参阅他对我的问题的评论,我现在知道为什么我会遇到这个特定问题)。

我需要在group 中转换select 语句可能不会返回匿名类型。 而不是这样,我需要返回一个类型化的对象。

这意味着我的代码需要更改为以下内容:

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

现在一切正常。 再次感谢。使用类型化代码比使用 BsonDocument 清晰得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-13
    • 2016-10-15
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多