使用C#计算嵌套对象的数量

时间:2018-05-08 23:17:09

标签: c# mongodb linq aggregation-framework

我正在使用ASP.Net core 2.0 web api开发一个软件。我需要计算我的集合中某些字段的数量。 我在MongoDB的集合中有数据,如下所示。我需要找到我的收藏中有多少个标签和多少个传感器。特定端点具有多个标签,每个标签具有多个传感器。

{
    "_id" : ObjectId("5aef51dfaf42ea1b70d0c4db"),    
    "EndpointId" : "89799bcc-e86f-4c8a-b340-8b5ed53caf83",    
    "DateTime" : ISODate("2018-05-06T19:05:02.666Z"),
    "Url" : "test",
    "Tags" : [ 
        {
            "Uid" : "C1:3D:CA:D4:45:11",
            "Type" : 1,
            "DateTime" : ISODate("2018-05-06T19:05:02.666Z"),
            "Sensors" : [ 
                {
                    "Type" : 1,
                    "Value" : NumberDecimal("-95")
                }, 
                {
                    "Type" : 2,
                    "Value" : NumberDecimal("-59")
                }, 
                {
                    "Type" : 3,
                    "Value" : NumberDecimal("11.029802536740132")
                }, 
                {
                    "Type" : 4,
                    "Value" : NumberDecimal("27.25")
                }, 
                {
                    "Type" : 6,
                    "Value" : NumberDecimal("2924")
                }
            ]
        },         
        {
            "Uid" : "C1:3D:CA:D4:45:11",
            "Type" : 1,
            "DateTime" : ISODate("2018-05-06T19:05:02.666Z"),
            "Sensors" : [ 
                {
                    "Type" : 1,
                    "Value" : NumberDecimal("-95")
                }, 
                {
                    "Type" : 2,
                    "Value" : NumberDecimal("-59")
                }, 
                {
                    "Type" : 3,
                    "Value" : NumberDecimal("11.413037961112279")
                }, 
                {
                    "Type" : 4,
                    "Value" : NumberDecimal("27.25")
                }, 
                {
                    "Type" : 6,
                    "Value" : NumberDecimal("2924")
                }
            ]
        },          
        {
            "Uid" : "E5:FA:2A:35:AF:DD",
            "Type" : 1,
            "DateTime" : ISODate("2018-05-06T19:05:02.666Z"),
            "Sensors" : [ 
                {
                    "Type" : 1,
                    "Value" : NumberDecimal("-97")
                }, 
                {
                    "Type" : 2,
                    "Value" : NumberDecimal("-58")
                }, 
                {
                    "Type" : 3,
                    "Value" : NumberDecimal("10.171658037099185")
                }
            ]
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("5aef51e0af42ea1b70d0c4dc"),    
    "EndpointId" : "89799bcc-e86f-4c8a-b340-8b5ed53caf83",    
    "Url" : "test",
    "Tags" : [ 
        {
            "Uid" : "E2:02:00:18:DA:40",
            "Type" : 1,
            "DateTime" : ISODate("2018-05-06T19:05:04.574Z"),
            "Sensors" : [ 
                {
                    "Type" : 1,
                    "Value" : NumberDecimal("-98")
                }, 
                {
                    "Type" : 2,
                    "Value" : NumberDecimal("-65")
                }, 
                {
                    "Type" : 3,
                    "Value" : NumberDecimal("7.845424441900629")
                }, 
                {
                    "Type" : 4,
                    "Value" : NumberDecimal("0.0")
                }, 
                {
                    "Type" : 6,
                    "Value" : NumberDecimal("3012")
                }
            ]
        }, 
        {
            "Uid" : "12:3B:6A:1A:B7:F9",
            "Type" : 1,
            "DateTime" : ISODate("2018-05-06T19:05:04.574Z"),
            "Sensors" : [ 
                {
                    "Type" : 1,
                    "Value" : NumberDecimal("-95")
                }, 
                {
                    "Type" : 2,
                    "Value" : NumberDecimal("-59")
                }, 
                {
                    "Type" : 3,
                    "Value" : NumberDecimal("12.939770381907275")
                }
            ]
        }
    ]
}

我想计算与特定EndpointId相关的标签和传感器的数量。如何在mongoDB中编写该查询?

1 个答案:

答案 0 :(得分:1)

查询"唯一"在"EndpointId"中的"Uid""Tags"中的"Type"中的"Sensors"内的db.collection.aggregate([ { "$unwind": "$Tags" }, { "$unwind": "$Tags.Sensors" }, { "$group": { "_id": { "EndpointId": "$EndpointId", "Uid": "$Tags.Uid", "Type": "$Tags.Sensors.Type" }, }}, { "$group": { "_id": { "EndpointId": "$_id.EndpointId", "Uid": "$_id.Uid", }, "count": { "$sum": 1 } }}, { "$group": { "_id": "$_id.EndpointId", "tagCount": { "$sum": 1 }, "sensorCount": { "$sum": "$count" } }} ]) 内出现的内容将是:

    var results = collection.AsQueryable()
      .SelectMany(p => p.Tags, (p, tag) => new
        {
          EndpointId = p.EndpointId,
          Uid = tag.Uid,
          Sensors = tag.Sensors
        }
      )
      .SelectMany(p => p.Sensors, (p, sensor) => new
        {
          EndpointId = p.EndpointId,
          Uid = p.Uid,
          Type = sensor.Type
        }
      )
      .GroupBy(p => new { EndpointId = p.EndpointId, Uid = p.Uid, Type = p.Type })
      .GroupBy(p => new { EndpointId = p.Key.EndpointId, Uid = p.Key.Uid },
        (k, s) => new { Key = k, count = s.Count() }
      )
      .GroupBy(p => p.Key.EndpointId,
        (k, s) => new
        {
          EndpointId = k,
          tagCount = s.Count(),
          sensorCount = s.Sum(x => x.count)
        }
      );

或者对于C#

{
  "EndpointId" : "89799bcc-e86f-4c8a-b340-8b5ed53caf83",
  "tagCount" : 4,
  "sensorCount" : 16
}

哪个输出:

"Uid"

虽然实际上是最有效的"这样做的方法考虑到所提供的文件具有$reduce的唯一值,无论如何都是db.collection.aggregate([ { "$group": { "_id": "$EndpointId", "tags": { "$sum": { "$size": { "$setUnion": ["$Tags.Uid",[]] } } }, "sensors": { "$sum": { "$sum": { "$map": { "input": { "$setUnion": ["$Tags.Uid",[]] }, "as": "tag", "in": { "$size": { "$reduce": { "input": { "$filter": { "input": { "$map": { "input": "$Tags", "in": { "Uid": "$$this.Uid", "Type": "$$this.Sensors.Type" } } }, "cond": { "$eq": [ "$$this.Uid", "$$tag" ] } } }, "initialValue": [], "in": { "$setUnion": [ "$$value", "$$this.Type" ] } } } } } } } } }} ]) 文件本身的金额:

BsonDocument

然而,该语句并不能很好地映射到LINQ,因此您需要使用"Uid"接口为语句构建BSON。当然,相同的$unwind值""实际上发生在集合中的多个文档中,然后"Tags"语句是必要的,以便" group"那些在数组条目中的文档中。

原始

您可以通过获取数组的$size来解决此问题。对于外部数组,这只是应用于文档中数组的字段路径,对于内部数组项,您需要使用$map进行处理,以便处理每个"Sensors"元素,然后获取{ {3}} db.collection.aggregate([ { "$project": { "tags": { "$size": "$Tags" }, "sensors": { "$sum": { "$map": { "input": "$Tags", "in": { "$size": "$$this.Sensors" } } } } }} ]) $size生成的数组减少到总计数。

每个文件都是:

collection.AsQueryable()
  .Select(p => new
    {
      tags = p.Tags.Count(),
      sensors = p.Tags.Select(x => x.Sensors.Count()).Sum()
    }
  );

您在C#代码中分配给类的位置如下:

{ "tags" : 3, "sensors" : 13 }
{ "tags" : 2, "sensors" : 8 }

返回的地方:

db.collection.aggregate([
  /* The shell would use $match for "query" conditions */
  //{ "$match": { "EndpointId": "89799bcc-e86f-4c8a-b340-8b5ed53caf83" } },
  { "$group": {
    "_id": null,
    "tags": { "$sum": { "$size": "$Tags" } },
    "sensors": {
      "$sum": {
        "$sum": {
          "$map": {
            "input": "$Tags",
             "in": { "$size": "$$this.Sensors" }
          }
        }
      }
    }
  }}
])

你想要$sum结果,例如在整个集合中,那么你会这样做:

collection.AsQueryable()
  .GroupBy(p => "", (k,s) => new
    {
      tags = s.Sum(p => p.Tags.Count()),
      sensors = s.Sum(p => p.Tags.Select(x => x.Sensors.Count()).Sum())
    }
  );

对于您之前的C#代码,将会是:

{ "tags" : 5, "sensors" : 21 }

返回的地方:

"EndpointId

对于null,您只需将该字段用作分组键,而不是{C}驱动程序映射应用的0collection.AsQueryable() /* Use the Where if you want a query to match only those documents */ //.Where(p => p.EndpointId == "89799bcc-e86f-4c8a-b340-8b5ed53caf83") .GroupBy(p => p.EndpointId, (k,s) => new { tags = s.Sum(p => p.Tags.Count()), sensors = s.Sum(p => p.Tags.Select(x => x.Sensors.Count()).Sum()) } );

{ "tags" : 5, "sensors" : 21 }

这当然是您给我们的两份文件样本的总和:

{{1}}

所以这些都是非常简单的结果,一旦习惯了语法,就可以执行简单的管道。

我建议您熟悉核心文档中的$group,当然还有Aggregation Operators表达式及其与C#驱动程序代码库的使用映射。

另请参阅C#驱动程序参考中的常规"LINQ Cheat Sheet",了解其如何映射到MongoDB的聚合框架的其他示例。