Pokud potřebujete něco takového vypočítat za běhu s „filtrovaným“ obsahem z pole určujícím pořadí řazení, pak nejlépe uděláte něco s .aggregate()
změnit tvar a určit hodnotu řazení takto:
db.collection.aggregate([
// Pre-filter the array elements
{ "$project": {
"tags": 1,
"score": {
"$setDifference": [
{ "$map": {
"input": "$tags",
"as": "tag",
"in": {
"$cond": [
{ "$eq": [ "$$el.id", "t1" ] },
"$$el.score",
false
]
}
}},
[false]
]
}
}},
// Unwind to denormalize
{ "$unwind": "$score" },
// Group back the "max" score
{ "$group": {
"_id": "$_id",
"tags": { "$first": "$tags" },
"score": { "$max": "$score" }
}},
// Sort descending by score
{ "$sort": { "score": -1 } }
])
Kde se první část kanálu používá k "předfiltrování" obsahu pole (stejně jako k zachování původního pole) pouze na ty hodnoty "skóre", kde se id rovná "t1". To se provádí zpracováním $map
který aplikuje podmínku na každý prvek prostřednictvím $cond
určit, zda vrátit "skóre" pro daný prvek nebo false
.
$setDifference
operace provede porovnání s polem jednoho prvku [false]
který účinně odstraní všechny false
hodnoty vrácené z $map
. Jako "set" to také odstraní duplicitní položky, ale pro účely třídění je to dobrá věc.
S polem redukovaným a přeformátovaným na hodnoty zpracujete $unwind
připraven na další fázi, kdy se bude zabývat hodnotami jako jednotlivými prvky. $group
fáze v podstatě platí $max
na "skóre", aby se vrátila nejvyšší hodnota obsažená ve filtrovaných výsledcích.
Pak už jen stačí použít $sort
na stanovenou hodnotu objednat doklady. Přirozeně, pokud to chcete naopak, použijte $min
a místo toho seřadit ve vzestupném pořadí.
Samozřejmě přidejte $match
fázi na začátek, pokud vše, co opravdu chcete, jsou dokumenty, které ve skutečnosti obsahují hodnoty "t1" pro id
v rámci značek. Ale tato část je nejméně relevantní pro třídění podle filtrovaných výsledků, kterých chcete dosáhnout.
Alternativou k počítání je dělat to všechno, když zapisujete položky do pole v dokumentech. Trochu chaotický, ale vypadá to nějak takto:
db.collection.update(
{ "_id": docId },
{
"$push": { "tags": { "id": "t1", "score": 60 } },
"$max": { "maxt1score": 60 },
"$min": { "mint1score": 60 }
}
)
Zde je $max
Operátor aktualizace nastaví hodnotu pro zadané pole pouze v případě, že je nová hodnota větší než stávající hodnota nebo jinak ještě neexistuje žádná vlastnost. Opačný případ platí pro $min
, kde pouze v případě, že bude menší než to, bude nahrazeno novou hodnotou.
To by samozřejmě mělo za následek přidání různých dalších vlastností do dokumentů, ale konečným výsledkem je řazení je značně zjednodušené:
db.collection.find().sort({ "maxt1score": -1 })
A poběží to mnohem rychleji než výpočty pomocí agregačního kanálu.
Zvažte tedy zásady návrhu. Strukturovaná data v polích, kde chcete filtrované a spárované výsledky pro třídění, znamenají výpočet za běhu, abyste určili, podle které hodnoty se mají třídit. Přidání dalších vlastností do dokumentu na .update()
znamená, že můžete jednoduše odkazovat na tyto vlastnosti a přímo třídit výsledky.