MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Изчислете броя на вложените обекти с C#

Заявката за преброяване на „уникалните“ появявания в рамките на "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" }
  }}
])

Или за C#

    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)
        }
      );

Кое извежда:

{
  "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" ] }
                }
              }
            }
          }
        }
      }
    }
  }}
])

Изявлението обаче не се съпоставя добре с LINQ, така че ще трябва да използвате BsonDocument интерфейс за изграждане на BSON за израза. И разбира се къде е същият "Uid" стойностите "did" всъщност се срещат в множество документи в колекцията, тогава $unwind изразите са необходими, за да ги „групирате“ заедно в документи от записите в масива.

Оригинал

Решавате това, като получите $size на масивите. За външния масив това просто се прилага към пътя на полето на масива в документа, а за елементите на вътрешния масив трябва да обработите с $map за да обработите всеки "Tags" елемент и след това получете $size на "Sensors" и $sum полученият масив да се намали до общия брой.

На документ, който би бил:

db.collection.aggregate([
  { "$project": {
    "tags": { "$size": "$Tags" },
    "sensors": {
      "$sum": {
        "$map": {
          "input": "$Tags",
           "in": { "$size": "$$this.Sensors" }
        }
      }
    }
  }}
])

Което къде сте присвоили на класове във вашия C# код ще бъде като:

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

Къде се връщат:

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

Къде искате да $group резултатите, като например върху цялата колекция, тогава бихте направили:

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" }
          }
        }
      }
    }
  }}
])

Което за вашия C# код, както преди, би било:

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())
    }
  );

Къде се връщат:

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

И за "EndpointId , тогава просто използвате това поле като ключ за групиране, вместо null или 0 тъй като се прилага от съпоставянето на C# драйвера:

collection.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 }

Така че това са много прости резултати, с просто конвейерно изпълнение, след като свикнете със синтаксиса.

Предлагам да се запознаете с операторите за агрегиране от основната документация и разбира се "LINQ Cheat Sheet" на изрази и картографиране на тяхното използване от хранилището на кода на C# Driver.

Вижте също общия Справочник за LINQ в справочника за C# драйвер за други примери за това как това се преобразува в рамката за агрегиране на MongoDB като цяло.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Защо Spark Mongo конекторът не натиска надолу филтрите?

  2. Как Spring Data знае кой магазин да подкрепи хранилище, ако се използват множество модули?

  3. Как да извлека и отпечатам обекти pymongo.cursor.Cursor?

  4. Базата данни за откриване на Mongoose не е готова

  5. Актуализиране на полето със стойност на друго поле в документа