Ujeté kilometry se mohou v tomto ohledu lišit a může se dobře ukázat, že „aktuálně“ proces, který sledujete, je přinejmenším „nejvhodnější“. Ale pravděpodobně to dokážeme efektivněji.
Co můžete nyní udělat
Za předpokladu, že jsou vaše pole již „seřazena“ pomocí $sort
modifikátor s $push
, pak pravděpodobně můžete udělat toto:
db.somedb.find(
{
"partn.is_partner": true,
"$where": function() {
return this.partn.slice(-1)[0].is_partner == true;
}
},
{ "partn": { "$slice": -1 } }
)
Tedy pokud partn,is_partner
je "indexovaný", je to stále docela efektivní, protože počáteční podmínka dotazu může být splněna pomocí indexu. Část, která nemůže, je $where
klauzule zde, která používá hodnocení JavaScriptu.
Ale co ta druhá část v $where
to, co dělá, je jednoduše "odříznout" poslední prvek z pole a otestovat jeho hodnotu is_partner
vlastnost, abyste zjistili, zda je to pravda. Pouze pokud je splněna i tato podmínka, je dokument vrácen.
K dispozici je také $slice
operátor projekce. To dělá totéž při vrácení posledního prvku z pole. Falešné shody jsou již filtrovány, takže se zobrazuje pouze poslední prvek, kde je pravda.
V kombinaci s indexem, jak bylo zmíněno, by to mělo být docela rychlé, protože dokumenty již byly vybrány a podmínka JavaScriptu pouze filtruje zbytek. Všimněte si, že bez dalšího pole s odpovídající standardní podmínkou dotazu $where
klauzule nemůže používat index. Snažte se tedy vždy používat „střídmě“ s jinými podmínkami dotazu.
Co můžete dělat v budoucnu
Next Up, i když není v době psaní tohoto článku k dispozici, ale určitě v blízké budoucnosti bude $slice
operátor pro agregační rámec. Toto je momentálně ve vývojové větvi, ale zde je náhled, jak to funguje:
db.somedb.aggregate([
{ "$match": { "partn.is_partner": true } },
{ "$redact": {
"$cond": {
"if": {
"$anyElementTrue": {
"$map": {
"input": { "$slice": ["$partn",-1] },
"as": "el",
"in": "$$el.is_partner"
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": {
"partn": { "$slice": [ "$partn",-1 ] }
}}
])
Kombinací tohoto $slice
v rámci $redact
fáze zde umožňuje filtrování dokumentů s logickou podmínkou, testování dokumentu. V tomto případě $slice
vytvoří pole jednoho prvku, které se odešle do $ mapa
za účelem extrahování jediného is_partner
hodnotu (stále jako pole). Protože se v nejlepším případě stále jedná o pole s jedním prvkem, dalším testem je $anyElementTrue
což z toho dělá singulární booleovský výsledek, vhodný pro $cond
.
$redact
zde rozhodne o tomto výsledku, zda $$KEEP
nebo $$PRUNE
dokument z výsledků. Později použijeme $slice
znovu v projektu, aby se po filtrování vrátil pouze poslední prvek pole.
Ukázalo se, že je to v podstatě přesně to, co dělá verze JavaScriptu, s tou výjimkou, že používá všechny nativní kódované operátory, a proto by měla být o něco rychlejší než alternativa JavaScriptu.
Oba formuláře vrátí váš první dokument podle očekávání:
{
"_id" : 0,
"partn" : [
{
"date" : ISODate("2015-07-28T00:59:14.963Z"),
"is_partner" : true
},
{
"date" : ISODate("2015-07-28T01:00:32.771Z"),
"is_partner" : false
},
{
"date" : ISODate("2015-07-28T01:15:29.916Z"),
"is_partner" : true
},
{
"date" : ISODate("2015-08-05T13:48:07.035Z"),
"is_partner" : false
},
{
"date" : ISODate("2015-08-05T13:50:56.482Z"),
"is_partner" : true
}
]
}
Velkým úlovkem u obou je, že vaše pole již musí být seřazeno, takže poslední datum je první. Bez toho pak potřebujete agregační rámec pro $sort
pole, stejně jako to děláte nyní.
Není to příliš efektivní, proto byste měli pole „předtřídit“ a udržovat pořadí při každé aktualizaci.
Jako praktický trik to ve skutečnosti změní pořadí všech prvků pole ve všech dokumentech kolekce jedním jednoduchým příkazem:
db.somedb.update(
{},
{ "$push": {
"partn": { "$each": [], "$sort": { "date": 1 } }
}},
{ "multi": true }
)
Takže i když „netlačíte“ nový prvek do pole a pouze aktualizujete vlastnost, vždy můžete použít tuto základní konstrukci, abyste zachovali uspořádání pole tak, jak chcete.
Stojí za zvážení, protože by to mělo věci mnohem rychleji urychlit.