Kilometertal kan variere på dette, og det kan meget vel vise sig, at "p.t." den proces, du følger, i hvert fald virker som "mest egnet". Men vi kan nok gøre mere effektivt.
Hvad du kunne gøre nu
Forudsat at dine arrays allerede er "sorteret" ved hjælp af <-koden>$sort
modifikator med $push
, så kan du sikkert gøre dette:
db.somedb.find(
{
"partn.is_partner": true,
"$where": function() {
return this.partn.slice(-1)[0].is_partner == true;
}
},
{ "partn": { "$slice": -1 } }
)
Så længe partn,is_partner
er "indekseret", er dette stadig ret effektivt, da den indledende forespørgselsbetingelse kan opfyldes ved hjælp af et indeks. Den del, der ikke kan, er $where
klausul her, der bruger JavaScript-evaluering.
Men hvad den anden del i $where
gør, er simpelthen at "skære" det sidste element fra arrayet og teste dets værdi af is_partner
ejendom for at se, om det er sandt. Kun hvis denne betingelse også er opfyldt, returneres dokumentet.
Der er også $slice
projektionsoperatør. Dette gør det samme ved at returnere det sidste element fra arrayet. Falske matches er allerede filtreret, så dette viser kun det sidste element, hvor sandt.
Kombineret med indekset som nævnt, så burde dette være ret hurtigt, da dokumenterne allerede er valgt og JavaScript-tilstanden bare filtrerer resten. Bemærk, at uden et andet felt med en standardforespørgselsbetingelse, der matcher, en $where
klausul kan ikke bruge et indeks. Så prøv altid at bruge "sparsomt" med andre forespørgselsbetingelser på plads.
Hvad du kan gøre i fremtiden
Next Up, selvom det ikke er tilgængeligt i skrivende stund, men helt sikkert i den nærmeste fremtid vil være $slice
operatør for aggregeringsrammen. Dette er i øjeblikket i udviklingsgrenen, men her er et kig på, hvordan det fungerer:
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 ] }
}}
])
Ved at kombinere det $slice
inden for en $redact
trin her tillader dokumenterne at blive filtreret med en logisk betingelse, test af dokumentet. I dette tilfælde $slice
producerer et enkelt element array, der sendes til $ kort
for blot at udtrække den enkelte is_partner
værdi (stadig som et array). Da dette i bedste fald stadig er et enkelt element-array, er den anden test >$anyElementTrue
hvilket gør dette til et enestående boolesk resultat, velegnet til $cond
.
$redact
her bestemmer resultatet om det skal $$KEEP
eller $$PRUNE
dokumentet fra resultaterne. Senere bruger vi $slice
igen i projektet for lige at returnere det sidste element i arrayet efter filtreringen.
Det viser sig at være stort set præcis, hvad JavaScript-versionen gør, med den undtagelse, at denne bruger alle indbyggede kodede operatorer, og derfor burde være en smule hurtigere end JavaScript-alternativet.
Begge formularer returnerer dit første dokument som forventet:
{
"_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
}
]
}
Den store fangst her med begge er, at dit array allerede skal være sorteret, så den seneste dato er først. Uden det har du brug for aggregeringsrammen til $sort
arrayet, ligesom du gør nu.
Ikke rigtig effektiv, så derfor bør du "forhåndssortere" dit array og vedligeholde rækkefølgen på hver opdatering.
Som et praktisk trick vil dette faktisk omarrangere alle array-elementer i alle samlingsdokumenter i en simpel erklæring:
db.somedb.update(
{},
{ "$push": {
"partn": { "$each": [], "$sort": { "date": 1 } }
}},
{ "multi": true }
)
Så selvom du ikke "skubber" et nyt element ind i et array og bare opdaterer en egenskab, kan du altid anvende den grundlæggende konstruktion for at holde arrayet i orden, som du vil have det.
Værd at overveje, da det burde gøre tingene meget hurtigere.