MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Oblicz liczbę zagnieżdżonych obiektów za pomocą C#

Zapytanie do zliczenia "unikalnych" wystąpień w "EndpointId" każdego z "Uid" w "Tags" i "Type" w "Sensors" byłoby:

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

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

Które wyjścia:

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

Chociaż faktycznie jest to "najwydajniejszy" sposób na zrobienie tego, biorąc pod uwagę, że prezentowane dokumenty mają unikalne wartości dla "Uid" tak czy inaczej byłoby $reduce kwoty w samych dokumentach:

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

Instrukcja nie jest jednak dobrze mapowana do LINQ, więc konieczne byłoby użycie BsonDocument interfejs do zbudowania BSON dla instrukcji. I oczywiście, gdzie ten sam "Uid" wartości "did" w rzeczywistości występują w wielu dokumentach w kolekcji, a następnie $unwind Instrukcje są niezbędne, aby "pogrupować" je w dokumentach z wpisów tablicy.

Oryginał

Możesz rozwiązać ten problem, uzyskując $size tablic. W przypadku tablicy zewnętrznej jest to po prostu zastosowanie do ścieżki pola tablicy w dokumencie, a dla elementów tablicy wewnętrznej, które należy przetworzyć za pomocą $map w celu przetworzenia każdego "Tags" a następnie uzyskaj $size z "Sensors" i $sum wynikową tablicę, aby zredukować do całkowitej liczby.

Na dokument, który byłby:

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

Które miejsce, w którym przypisałeś zajęcia w swoim kodzie C#, wyglądałoby następująco:

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

Gdzie te wracają:

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

Gdzie chcesz $group wyniki, jak na przykład w całej kolekcji, to byś zrobił:

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

Które dla twojego kodu C#, jak wcześniej, byłoby:

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

Gdzie te wracają:

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

A dla "EndpointId , po prostu użyj tego pola jako klucza grupującego, a nie null lub 0 jak jest stosowany przez mapowanie sterownika 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())
    }
  );

Jest to oczywiście ta sama suma dwóch próbek dokumentów, które nam przekazałeś:

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

Są to więc bardzo proste wyniki, z prostym wykonaniem potoku, gdy przyzwyczaisz się do składni.

Proponuję zapoznać się z Operatorami agregacji z podstawowej dokumentacji i oczywiście "Ściągawka LINQ" wyrażeń i mapowanie ich użycia z repozytorium kodu sterownika C#.

Zobacz także ogólne LINQ Reference w dokumentacji sterownika C#, aby zapoznać się z innymi przykładami tego, jak to mapuje się ogólnie na strukturę agregacji MongoDB.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Wypełnij obiekt w tablicy

  2. Serializacja sterownika MongoDB C# z obiektami dynamicznymi

  3. Skonfiguruj pymongo, aby używał ciągu _id zamiast ObjectId

  4. Spring MongoTemplate - znajdź według regex w kolekcji

  5. Mongoexport do wielu plików csv