如何在C#中使用linq / mongodb平均非空值

时间:2019-06-29 22:33:04

标签: c# mongodb linq

我有一个表,其中对象的字段标记为 BsonIgnoreIfDefault

反序列化对象时,字段显示为空。

我正在尝试对使用AsQueryable()解析的集合进行平均。

查询如下:

            var Result = db.Collection.AsQueryable()
                .Where(_ => _.TimeStamp >= From && _.TimeStamp < To)
                .GroupBy(_ => true)  // not sure why, but I can't compile without this
                .Select(_ => new
                    {
                        R = new Result
                        {
                            TimeStamp = From,
                            i = _.Average(P => P.i)
                        },
                        Count = _.Count()
                    }
                ).FirstOrDefault();

,但是有时 i 字段为空。这样进行平均时如何跳过空值?

对象就像

class A
{
    public DateTime TimeStamp;
    [BsonIgnoreIfDefault]
    public double i;
}

此外,我发现反序列化时,对象不能保持空;所以我想找到如何仅对具有 i

属性的对象求平均

1 个答案:

答案 0 :(得分:-1)

简单的解决方案是使用可为空的double属性double?。这是产生预期结果的完整解决方案。

using MongoDB.Entities;
using System;
using System.Linq;

namespace StackOverflow
{
    public class Program
    {
        public class Record : Entity
        {
            public DateTime TimeStamp { get; set; }
            public double? Value { get; set; }
        }

        private static void Main(string[] args)
        {
            new DB("test");

            (new[] {
                new Record { TimeStamp = DateTime.UtcNow },
                new Record { TimeStamp = DateTime.UtcNow, Value = null },
                new Record { TimeStamp = DateTime.UtcNow, Value = 2 },
                new Record { TimeStamp = DateTime.UtcNow, Value = 2 }
            }).Save();

            var from = DateTime.UtcNow.AddMinutes(-1);
            var to = DateTime.UtcNow.AddMinutes(1);

            var result = DB.Queryable<Record>()
                           .Where(r => r.Value != null && r.TimeStamp >= from && r.TimeStamp <= to)
                           .GroupBy(r => true)
                           .Select(g => new
                           {
                               Rec = new Record { TimeStamp = from, Value = g.Average(r => r.Value) },
                               Count = g.Count()
                           })
                           .Single();

            Console.WriteLine($"Average: {result.Rec.Value}");
            Console.WriteLine($"Count: {result.Count}");
            Console.ReadKey();

        }
    }
}

上面使用的是我的库 MongoDB.Entities ,但查询部分与官方驱动程序的.AsQueryable相同。

它将产生以下聚合查询:

db.Record.aggregate([
    {
        "$match": {
            "Value": {
                "$ne": null
            },
            "TimeStamp": {
                "$gte": ISODate("2019-06-30T07:20:59.126Z"),
                "$lte": ISODate("2019-06-30T07:22:59.126Z")
            }
        }
    },
    {
        "$group": {
            "_id": true,
            "__agg0": {
                "$avg": "$Value"
            },
            "__agg1": {
                "$sum": NumberInt("1")
            }
        }
    },
    {
        "$project": {
            "Rec": {
                "TimeStamp": ISODate("2019-06-30T07:20:59.126Z"),
                "Value": "$__agg0"
            },
            "Count": "$__agg1",
            "_id": NumberInt("0")
        }
    }
])