MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Hitung jumlah objek bersarang dengan C#

Kueri untuk menghitung kemunculan "unik" dalam "EndpointId" dari masing-masing "Uid" di "Tags" dan "Type" di "Sensors" akan menjadi:

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

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

Keluaran mana:

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

Padahal sebenarnya cara "paling efisien" untuk melakukan ini mengingat dokumen yang disajikan memiliki nilai unik untuk "Uid" tetap akan menjadi $reduce jumlah dalam dokumen itu sendiri:

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

Pernyataan tersebut tidak benar-benar memetakan dengan baik ke LINQ, jadi Anda akan diminta untuk menggunakan BsonDocument antarmuka untuk membangun BSON untuk pernyataan tersebut. Dan tentu saja di mana "Uid" yang sama nilai "did" sebenarnya terjadi dalam beberapa dokumen dalam koleksi, lalu $unwind pernyataan diperlukan untuk "mengelompokkan" mereka bersama-sama di seluruh dokumen dari dalam entri array.

Asli

Anda mengatasi ini dengan mendapatkan $size dari array. Untuk larik luar, ini hanya berlaku untuk jalur bidang larik dalam dokumen, dan untuk item larik dalam Anda perlu memproses dengan $map untuk memproses setiap "Tags" lalu dapatkan $size dari "Sensors" dan $sum array yang dihasilkan untuk mengurangi jumlah keseluruhan.

Per dokumen yang akan menjadi:

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

Di mana Anda telah menetapkan kelas dalam kode C# Anda akan menjadi seperti:

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

Di mana mereka kembali:

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

Di mana Anda ingin $group hasilnya, misalkan ke seluruh koleksi, maka Anda akan melakukan:

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

Yang untuk kode C# Anda seperti sebelumnya adalah:

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

Di mana mereka kembali:

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

Dan untuk "EndpointId , maka Anda cukup menggunakan bidang itu sebagai kunci pengelompokan, bukan null atau 0 seperti yang diterapkan oleh pemetaan driver 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())
    }
  );

Yang tentu saja jumlah yang sama dari dua contoh dokumen yang Anda berikan kepada kami:

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

Jadi ini adalah hasil yang sangat sederhana, dengan eksekusi pipeline sederhana setelah Anda terbiasa dengan sintaksnya.

Saya sarankan untuk membiasakan diri Anda dengan Operator Agregasi dari dokumentasi inti, dan tentu saja "Lembar Cheat LINQ" ekspresi dan pemetaan penggunaannya dari dalam repositori kode Driver C#.

Lihat juga Referensi LINQ umum dalam referensi Driver C# untuk contoh lain tentang bagaimana ini memetakan ke Kerangka Agregasi MongoDB secara umum.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. cara membuat objek mongoDB di java

  2. Permintaan berbeda dengan MongoMapper

  3. Wildcard notasi titik Mongodb?

  4. Menyimpan dan mengambil objek JavaScript di/dari MongoDB

  5. Perbarui properti yang sama dari setiap dokumen koleksi mongoDb dengan nilai yang berbeda