Körsträckan kan variera på detta och det kan mycket väl visa sig att "för närvarande" den process du följer verkar vara "mest lämpad" åtminstone. Men vi kan nog göra mer effektivt.
Vad du kan göra nu
Förutsatt att dina arrayer redan är "sorterade" med hjälp av <-koden>$sort
modifierare med $push
, då kan du förmodligen göra så här:
db.somedb.find(
{
"partn.is_partner": true,
"$where": function() {
return this.partn.slice(-1)[0].is_partner == true;
}
},
{ "partn": { "$slice": -1 } }
)
Så länge som partn,is_partner
är "indexerad" är detta fortfarande ganska effektivt eftersom det initiala frågevillkoret kan uppfyllas med ett index. Den del som inte kan är $where
klausul här som använder JavaScript-utvärdering.
Men vad den andra delen i $where
gör är att helt enkelt "skiva" det sista elementet från arrayen och testa dess värde för is_partner
egendom för att se om det är sant. Endast om det villkoret också är uppfyllt returneras dokumentet.
Det finns också $slice
projektionsoperatör. Detta gör samma sak för att returnera det sista elementet från arrayen. Falska matchningar är redan filtrerade, så detta visar bara det sista elementet där sant.
I kombination med indexet som nämnts så borde detta gå ganska snabbt med tanke på att dokumenten redan har valts och JavaScript-villkoret bara filtrerar resten. Observera att utan ett annat fält med ett standardfrågevillkor att matcha, en $where
klausul kan inte använda ett index. Så försök alltid att använda "sparsamt" med andra frågevillkor på plats.
Vad du kan göra i framtiden
Next Up, även om det inte är tillgängligt i skrivande stund, men kommer säkerligen inom en snar framtid att vara $slice
operatör för aggregeringsramverket. Detta är för närvarande i utvecklingsgrenen, men här är en titt på hur det fungerar:
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 ] }
}}
])
Att kombinera den $slice
inom en $redact
steg här tillåter att dokumenten filtreras med ett logiskt villkor och testar dokumentet. I det här fallet $slice
producerar en enstaka elementarray som skickas till $ karta
för att bara extrahera singeln is_partner
värde (fortfarande som en array). Eftersom detta i bästa fall fortfarande är en enstaka elementarray är det andra testet
strong>$anyElementTrue
vilket gör detta till ett unikt booleskt resultat, lämpligt för $cond
.
$redact
här bestämmer resultatet om det ska $$KEEP
eller $$PRUNE
dokumentet från resultaten. Senare använder vi $slice
igen i projektet för att bara returnera det sista elementet i arrayen efter filtreringen.
Det verkar vara i stort sett exakt vad JavaScript-versionen gör, med undantaget att den här använder alla inbyggda kodade operatorer och därför borde vara lite snabbare än JavaScript-alternativet.
Båda formulären returnerar ditt första dokument som förväntat:
{
"_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 stora haken här med båda är att din array redan måste vara sorterad så det senaste datumet är först. Utan det behöver du aggregeringsramverket för att $sortera
arrayen, precis som du gör nu.
Inte riktigt effektivt, så det är därför du bör "försortera" din array och behålla ordningen på varje uppdatering.
Som ett praktiskt knep kommer detta faktiskt att ordna om alla arrayelement i alla samlingsdokument i ett enkelt uttalande:
db.somedb.update(
{},
{ "$push": {
"partn": { "$each": [], "$sort": { "date": 1 } }
}},
{ "multi": true }
)
Så även om du inte "skjuter in" ett nytt element i en array och bara uppdaterar en egenskap, kan du alltid tillämpa den grundläggande konstruktionen för att hålla arrayen ordnad som du vill ha den.
Värt att överväga eftersom det borde göra saker mycket snabbare.