Pertama, mari tunjukkan data Anda dengan cara yang dapat digunakan orang lain dan menghasilkan hasil yang diinginkan:
{ value: 1,
_id: ObjectId('5cb9ea0c75c61525e0176f96'),
name: 'Test',
category: 'Development',
subcategory: 'Programming Languages',
status: 'Supported',
description: 'Test',
change:
[ { version: 1,
who: 'ATL User',
when: new Date('2019-04-19T15:30:39.912Z'),
what: 'Item Creation' },
{ version: 2,
who: 'ATL Other User',
when: new Date('2019-04-19T15:31:39.912Z'),
what: 'Name Change' } ],
}
Perhatikan bahwa "when"
tanggal sebenarnya berbeda sehingga akan ada $max
nilai dan mereka tidak hanya sama. Sekarang kita bisa menjalankan kasusnya
Kasus 1 - Ambil "tunggal" $max
nilai
Kasus dasar di sini adalah menggunakan $arrayElemAt
dan $indexOfArray
operator untuk mengembalikan $max
yang cocok
nilai:
db.items.aggregate([
{ "$match": {
"subcategory": "Programming Languages", "name": { "$exists": true }
}},
{ "$addFields": {
"change": {
"$arrayElemAt": [
"$change",
{ "$indexOfArray": [
"$change.when",
{ "$max": "$change.when" }
]}
]
}
}}
])
Pengembalian:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : {
"version" : 2,
"who" : "ATL Other User",
"when" : ISODate("2019-04-19T15:31:39.912Z"),
"what" : "Name Change"
}
}
Pada dasarnya "$max": "$change.when"
mengembalikan nilai yang merupakan "maksimum" dari dalam array nilai tersebut. Anda kemudian menemukan "indeks" yang cocok dari larik nilai tersebut melalui $indexOfArray
yang mengembalikan pertama indeks yang cocok ditemukan. Posisi "indeks" itu (dari sebenarnya hanya array "when"
nilai dialihkan dalam urutan yang sama ) kemudian digunakan dengan $arrayElemAt
untuk mengekstrak "seluruh objek" dari "change"
array pada posisi indeks yang ditentukan.
Kasus 2 - Mengembalikan "multiple" $max
entri
Hampir sama dengan $max
, kecuali kali ini kami $filter
untuk mengembalikan beberapa "mungkin" nilai yang cocok dengan $max
nilai:
db.items.aggregate([
{ "$match": {
"subcategory": "Programming Languages", "name": { "$exists": true }
}},
{ "$addFields": {
"change": {
"$filter": {
"input": "$change",
"cond": {
"$eq": [ "$$this.when", { "$max": "$change.when" } ]
}
}
}
}}
])
Pengembalian:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : [
{
"version" : 2,
"who" : "ATL Other User",
"when" : ISODate("2019-04-19T15:31:39.912Z"),
"what" : "Name Change"
}
]
}
Jadi $max
tentu saja sama tetapi kali ini nilai tunggal yang dikembalikan oleh operator tersebut digunakan dalam $eq
perbandingan dalam $filter
. Ini memeriksa setiap elemen array dan melihat saat ini "when"
nilai ( "$$this.when"
). Dimana "sama" maka elemen tersebut dikembalikan.
Pada dasarnya sama dengan pendekatan pertama tetapi dengan pengecualian bahwa $filter
memungkinkan "banyak" elemen yang akan dikembalikan. Oleh karena itu semuanya dengan sama $max
nilai.
Kasus 3 - Pra-sortir konten array.
Sekarang Anda mungkin memperhatikan bahwa dalam contoh data yang saya sertakan ( diadaptasi dari data Anda sendiri tetapi dengan tanggal "maks" yang sebenarnya ) nilai "maks" sebenarnya adalah terakhir nilai dalam larik. Ini mungkin terjadi secara alami sebagai akibat $push
( secara default ) "tambahkan" ke akhir konten array yang ada. Jadi "lebih baru" entri akan cenderung berada di akhir dari larik.
Ini tentu saja default perilaku, tetapi ada alasan bagus mengapa Anda "mungkin" ingin mengubah itu. Singkatnya terbaik cara untuk mendapatkan "paling baru" entri array sebenarnya mengembalikan elemen pertama dari larik.
Yang perlu Anda lakukan hanyalah memastikan "terbaru" sebenarnya ditambahkan pertama daripada terakhir . Ada dua pendekatan:
-
Gunakan
$position
ke item larik yang "ditunda dulu": Ini adalah pengubah sederhana untuk$push
menggunakan0
posisi untuk selalu menambah depan :db.items.updateOne( { "_id" : ObjectId("5cb9ea0c75c61525e0176f96") }, { "$push": { "change": { "$each": [{ "version": 3, "who": "ATL User", "when": new Date(), "what": "Another change" }], "$position": 0 } }} )
Ini akan mengubah dokumen menjadi:
{ "_id" : ObjectId("5cb9ea0c75c61525e0176f96"), "value" : 1, "name" : "Test", "category" : "Development", "subcategory" : "Programming Languages", "status" : "Supported", "description" : "Test", "change" : [ { "version" : 3, "who" : "ATL User", "when" : ISODate("2019-04-20T02:40:30.024Z"), "what" : "Another change" }, { "version" : 1, "who" : "ATL User", "when" : ISODate("2019-04-19T15:30:39.912Z"), "what" : "Item Creation" }, { "version" : 2, "who" : "ATL Other User", "when" : ISODate("2019-04-19T15:31:39.912Z"), "what" : "Name Change" } ] }
Perhatikan bahwa ini akan mengharuskan Anda untuk benar-benar pergi dan "membalikkan" semua elemen array Anda sebelumnya sehingga "terbaru" sudah ada di depan sehingga urutannya dipertahankan. Untungnya ini agak tercakup dalam pendekatan kedua...
-
Gunakan
$sort
untuk mengubah dokumen secara berurutan pada setiap$push
: Dan ini adalah pengubah lain yang sebenarnya "mengurutkan ulang" secara atom pada setiap penambahan item baru. Penggunaan normal pada dasarnya sama dengan item baru apa pun ke$each
seperti di atas, atau bahkan hanya larik "kosong" untuk menerapkan$sort
hanya untuk data yang ada:db.items.updateOne( { "_id" : ObjectId("5cb9ea0c75c61525e0176f96") }, { "$push": { "change": { "$each": [], "$sort": { "when": -1 } } }} )
Hasil dalam:
{ "_id" : ObjectId("5cb9ea0c75c61525e0176f96"), "value" : 1, "name" : "Test", "category" : "Development", "subcategory" : "Programming Languages", "status" : "Supported", "description" : "Test", "change" : [ { "version" : 3, "who" : "ATL User", "when" : ISODate("2019-04-20T02:40:30.024Z"), "what" : "Another change" }, { "version" : 2, "who" : "ATL Other User", "when" : ISODate("2019-04-19T15:31:39.912Z"), "what" : "Name Change" }, { "version" : 1, "who" : "ATL User", "when" : ISODate("2019-04-19T15:30:39.912Z"), "what" : "Item Creation" } ] }
Mungkin perlu beberapa saat untuk memahami mengapa Anda
$push
untuk$sort
larik seperti ini, tetapi maksud umumnya adalah ketika modifikasi dapat dilakukan pada larik yang "mengubah" properti sepertiDate
nilai sedang diurutkan dan Anda akan menggunakan pernyataan seperti itu untuk mencerminkan perubahan tersebut. Atau memang hanya menambahkan item baru dengan$sort
dan biarkan berhasil.
Jadi mengapa "menyimpan" array dipesan seperti ini? Seperti yang disebutkan sebelumnya, Anda menginginkan yang pertama item sebagai "paling baru" , lalu kueri untuk mengembalikan yang menjadi:
db.items.find(
{
"subcategory": "Programming Languages",
"name": { "$exists": true }
},
{ "change": { "$slice": 1 } }
)
Pengembalian:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : [
{
"version" : 3,
"who" : "ATL User",
"when" : ISODate("2019-04-20T02:40:30.024Z"),
"what" : "Another change"
}
]
}
Jadi $slice
kemudian dapat digunakan hanya untuk mengekstrak item array dengan indeks yang diketahui. Secara teknis Anda bisa menggunakan -1
di sana untuk mengembalikan terakhir item dari array, tetapi penataan ulang di mana yang terbaru adalah yang pertama memungkinkan hal-hal lain seperti mengonfirmasi modifikasi terakhir dibuat oleh pengguna tertentu, dan/atau kondisi lain seperti batasan rentang tanggal. yaitu:
db.items.find(
{
"subcategory": "Programming Languages",
"name": { "$exists": true },
"change.0.who": "ATL User",
"change.0.when": { "$gt": new Date("2018-04-01") }
},
{ "change": { "$slice": 1 } }
)
Perhatikan di sini bahwa sesuatu seperti "change.-1.when"
adalah pernyataan ilegal, itulah sebabnya kami menyusun ulang array sehingga Anda dapat menggunakan legal 0
untuk pertama bukannya -1
untuk terakhir .
Kesimpulan
Jadi ada beberapa hal berbeda yang dapat Anda lakukan, baik dengan menggunakan pendekatan agregasi untuk memfilter konten array atau melalui formulir kueri standar setelah melakukan beberapa modifikasi pada bagaimana data sebenarnya disimpan. Yang mana yang akan digunakan bergantung pada keadaan Anda sendiri, tetapi perlu diperhatikan bahwa salah satu formulir kueri standar akan berjalan lebih cepat daripada manipulasi apa pun melalui kerangka kerja agregasi atau operator terkomputasi mana pun.