Alcune cose che puoi fare qui:
Prima di tutto, usa $in invece di $or.
In secondo luogo, MongoDB può solo usa un indice per la tua prima partita, quindi dovrai decidere (provandoci) quale delle due partite è migliore. L'obiettivo è avere una query più veloce e meno documenti che passano attraverso la pipeline. Per questo fai le seguenti cose:
Innanzitutto, crea i tre indici:
db.element.ensureIndex( { 'versions.branch' : 1 } );
db.element.ensureIndex( { 'doctype' : 1 } );
db.element.ensureIndex( { 'prefix' : 1 } );
Quindi esegui le tre query seguenti e nota i campi "cursor", "n", "nScanned" e "ms":
branch = "nameofbranch"; // guessing here
db.element.find( "versions.branch": branch ).explain();
db.element.find( "doctype" { $in: [ "15281", "15282" .... ] } ).explain();
db.element.find( "prefix": { $ne: "500" } ).explain();
Per l'ultima query, noterai che "cursor" è "BasicCursor", perché una query $ne non può utilizzare l'indice.
Gli altri due ti mostreranno vari valori per "ms", "n" e "nScanned". "ms" è il tempo impiegato per eseguire la query. Se è approssimativamente lo stesso, osserva la differenza tra i valori "n" e "nScanned". Mi aspetto e immagino che la differenza per la query "versions.branch" sia 0. Per la query "doctype" potrebbe essere diversa. Se "ms" non è approssimativamente lo stesso, metti la corrispondenza $ che era la più veloce first come clausola $match nella pipeline di aggregazione.
Se la velocità ("ms") è la stessa, controllare i valori "n". Se la "n" per la query "prefisso" è "5" e la "n" per la query "versions.branch" è "500", significa che il risultato della query "prefisso" è migliore, in quanto meno i documenti vengono restituiti. In tal caso, inseriscila come prima clausola $match in totale. Se "versions.branch" è molto inferiore, usa quella come prima clausola $match.