Selama data Anda memiliki sensor unik dan pembacaan tag per dokumen, yang sampai saat ini tampak seperti apa yang telah Anda presentasikan, maka Anda tidak perlu $unwind
sama sekali.
Faktanya, yang Anda butuhkan hanyalah satu $group
:
db.endpoints.aggregate([
// In reality you would $match to limit the selection of documents
{ "$match": {
"DateTime": { "$gte": new Date("2018-05-01"), "$lt": new Date("2018-06-01") }
}},
{ "$group": {
"_id": "$EndpointId",
"FirstActivity" : { "$min" : "$DateTime" },
"LastActivity" : { "$max" : "$DateTime" },
"RequestCount": { "$sum": 1 },
"TagCount": {
"$sum": {
"$size": { "$setUnion": ["$Tags.Uid",[]] }
}
},
"SensorCount": {
"$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" ] }
}
}
}
}
}
}
}
}}
])
Atau jika Anda benar-benar perlu mengumpulkan nilai "unik" dari "Sensor" dan "Tag" dari berbagai dokumen, maka Anda masih memerlukan $unwind
pernyataan untuk mendapatkan pengelompokan yang tepat, tetapi tidak sebanyak yang Anda miliki saat ini:
db.endpoints.aggregate([
// In reality you would $match to limit the selection of documents
{ "$match": {
"DateTime": { "$gte": new Date("2018-05-01"), "$lt": new Date("2018-06-01") }
}},
{ "$unwind": "$Tags" },
{ "$unwind": "$Tags.Sensors" },
{ "$group": {
"_id": {
"EndpointId": "$EndpointId",
"Uid": "$Tags.Uid",
"Type": "$Tags.Sensors.Type"
},
"FirstActivity": { "$min": "$DateTime" },
"LastActivity": { "$max": "$DateTime" },
"RequestCount": { "$addToSet": "$_id" }
}},
{ "$group": {
"_id": {
"EndpointId": "$_id.EndpointId",
"Uid": "$_id.Uid",
},
"FirstActivity": { "$min": "$FirstActivity" },
"LastActivity": { "$max": "$LastActivity" },
"count": { "$sum": 1 },
"RequestCount": { "$addToSet": "$RequestCount" }
}},
{ "$group": {
"_id": "$_id.EndpointId",
"FirstActivity": { "$min": "$FirstActivity" },
"LastActivity": { "$max": "$LastActivity" },
"TagCount": { "$sum": 1 },
"SensorCount": { "$sum": "$count" },
"RequestCount": { "$addToSet": "$RequestCount" }
}},
{ "$addFields": {
"RequestCount": {
"$size": {
"$reduce": {
"input": {
"$reduce": {
"input": "$RequestCount",
"initialValue": [],
"in": { "$setUnion": [ "$$value", "$$this" ] }
}
},
"initialValue": [],
"in": { "$setUnion": [ "$$value", "$$this" ] }
}
}
}
}}
],{ "allowDiskUse": true })
Dan dari MongoDB 4.0 Anda dapat menggunakan $toString
pada ObjectId
dalam _id
dan cukup gabungkan kunci unik untuk menjaga RequestCount
menggunakan $mergeObjects
. Ini lebih bersih dan sedikit lebih terukur daripada mendorong konten array bersarang dan meratakannya
db.endpoints.aggregate([
// In reality you would $match to limit the selection of documents
{ "$match": {
"DateTime": { "$gte": new Date("2018-05-01"), "$lt": new Date("2018-06-01") }
}},
{ "$unwind": "$Tags" },
{ "$unwind": "$Tags.Sensors" },
{ "$group": {
"_id": {
"EndpointId": "$EndpointId",
"Uid": "$Tags.Uid",
"Type": "$Tags.Sensors.Type"
},
"FirstActivity": { "$min": "$DateTime" },
"LastActivity": { "$max": "$DateTime" },
"RequestCount": {
"$mergeObjects": {
"$arrayToObject": [[{ "k": { "$toString": "$_id" }, "v": 1 }]]
}
}
}},
{ "$group": {
"_id": {
"EndpointId": "$_id.EndpointId",
"Uid": "$_id.Uid",
},
"FirstActivity": { "$min": "$FirstActivity" },
"LastActivity": { "$max": "$LastActivity" },
"count": { "$sum": 1 },
"RequestCount": { "$mergeObjects": "$RequestCount" }
}},
{ "$group": {
"_id": "$_id.EndpointId",
"FirstActivity": { "$min": "$FirstActivity" },
"LastActivity": { "$max": "$LastActivity" },
"TagCount": { "$sum": 1 },
"SensorCount": { "$sum": "$count" },
"RequestCount": { "$mergeObjects": "$RequestCount" }
}},
{ "$addFields": {
"RequestCount": {
"$size": {
"$objectToArray": "$RequestCount"
}
}
}}
],{ "allowDiskUse": true })
Bentuk mana pun mengembalikan data yang sama, meskipun urutan kunci dalam hasil mungkin berbeda:
{
"_id" : "89799bcc-e86f-4c8a-b340-8b5ed53caf83",
"FirstActivity" : ISODate("2018-05-06T19:05:02.666Z"),
"LastActivity" : ISODate("2018-05-06T19:05:02.666Z"),
"RequestCount" : 2,
"TagCount" : 4,
"SensorCount" : 16
}
Hasilnya diperoleh dari dokumen sampel yang awalnya Anda berikan sebagai sumber sampel di pertanyaan awal tentang topik :
{
"_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")
}
]
}
]
}
Intinya adalah Anda dapat menggunakan formulir yang diberikan pertama di sini yang akan terakumulasi "dalam setiap dokumen" dan kemudian "terakumulasi per titik akhir" dalam satu tahap dan merupakan yang paling optimal, atau Anda benar-benar perlu mengidentifikasi hal-hal seperti "Uid"
pada tag atau "Type"
pada sensor di mana nilai-nilai tersebut muncul lebih dari sekali pada kombinasi dokumen apa pun yang dikelompokkan berdasarkan titik akhir.
Data sampel yang Anda berikan hingga saat ini hanya menunjukkan bahwa nilai-nilai ini "unik dalam setiap dokumen", oleh karena itu formulir yang diberikan pertama akan paling optimal jika ini berlaku untuk semua data yang tersisa.
Jika tidak, maka "melepaskan" dua array bersarang untuk "menggabungkan detail di seluruh dokumen" adalah satu-satunya cara untuk mendekati ini. Anda dapat membatasi rentang tanggal atau kriteria lain karena sebagian besar "kueri" biasanya memiliki beberapa batasan dan tidak benar-benar berfungsi pada data koleksi "keseluruhan", tetapi fakta utamanya tetap bahwa array akan "dibatalkan" pada dasarnya membuat salinan dokumen untuk setiap anggota larik.
Intinya pada optimasi berarti Anda hanya perlu melakukan ini "dua kali" karena hanya ada dua array. Melakukan $group
berturut-turut
ke $unwind
ke $group
selalu merupakan tanda pasti Anda melakukan sesuatu yang benar-benar salah. Setelah Anda "membongkar sesuatu", Anda hanya perlu "memasang kembali" sekali . Dalam serangkaian langkah bertingkat seperti yang ditunjukkan di sini adalah sekali pendekatan yang mengoptimalkan.
Di luar cakupan pertanyaan Anda tetap ada:
- Tambahkan batasan realistis lainnya ke kueri untuk mengurangi dokumen yang diproses, bahkan mungkin melakukannya dalam "batch" dan menggabungkan hasil
- Tambahkan
allowDiskUse
pilihan untuk pipa untuk membiarkan penyimpanan sementara digunakan. ( sebenarnya ditunjukkan pada perintah ) - Pertimbangkan bahwa "array bersarang" mungkin bukan metode penyimpanan terbaik untuk analisis yang ingin Anda lakukan. Itu selalu lebih efisien ketika Anda tahu Anda perlu
$unwind
untuk hanya menulis data dalam bentuk "dibatalkan" itu langsung ke dalam koleksi.