javascript - Je možné, aby asynchrónna funkcia vrátila mongoose Query namiesto Promise?
Nastavenie
Povedzme, že máme niekoľko dokumentov Foo a Bar. Foo má pole name, ktoré je možné použiť na identifikáciu dokumentov okrem použitia _id dokumentu. Bar obsahuje odkaz na dokument Foo.
const fooSchema = new mongoose.Schema({
name: {
type: String,
unique: true
}
});
const Foo = <any>mongoose.model<any>('Foo', fooSchema);
const barSchema = new mongoose.Schema({
foo: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Foo'
},
date: Date
});
const Bar = <any>mongoose.model<any>('Bar', barSchema);
Predpokladajme, že teraz máme name dokumentu Foo, ale nie jeho _id. Chceme nájsť všetky dokumenty Bar, ktoré odkazujú na tento dokument Foo. Takže napíšeme funkciu, ktorá najprv nájde dokument Foo s daným name a potom ho použije na nájdenie dokumentov Bar.
barSchema.statics.findBarWithFooName = async function(name: string) {
let foo = await Foo.findOne({ name: name });
return Bar.find({ foo: foo });
};
A túto funkciu môžeme použiť takto:
let bars = await Bar.findBarWithFooName('fooName');
Problém
Avšak, chceme tiež zoradiť bars podľa dátumu. Normálne, s Query builderom od mongoose, môžeme napísať niečo takéto:
let bars = await Bar.find({})
.sort('date');
Avšak, ak by sme namiesto toho použili funkciu, ktorú sme napísali:
let bars = await Bar.findBarWithFooName('fooName')
.sort('date');
Namiesto toho by sme dostali chybu:
Upozornenie: Nezachytené odmietnutie sľubu (ID odmietnutia: 1): TypeError: Bar.findBarWithFooName(...).sort nie je funkcia
Ladenie
Pri skúmaní pomocou console.log(bars) som zistil, že keď zavoláme Bar.find({}), výsledný objekt je objekt Query od mongoose.
Avšak, keď zavoláme Bar.findBarWithFooName('fooName'), výsledný objekt je Promise { <pending> }. Takže je pochopiteľné, že metóda sort neexistuje na Promise { <pending> }.
Otázka
Moja otázka teda znie, prečo v prvom prípade vracia Query, ale v druhom prípade vracia Promise { <pending> }? A čo môžem urobiť, aby findBarWithFooName vracalo Query, aby som mohol pokračovať v budovaní dotazu, namiesto Promise { <pending> }?
Som si vedomý, že jedno riešenie, ktoré môžem použiť, je vybrať await Foo.findOne({ name: name }) z findBarWithFooName a jednoducho vziať _id ako parameter namiesto name. Avšak, snažím sa abstrahovať proces nutnosti najprv nájsť Foo, preto sa snažím vytvoriť jednu funkciu, ktorá namiesto toho vráti Query.
Odpoveď č. 1
Nie
Je nemožné, aby async funkcia vrátila vlastný objekt namiesto Promise - dokonca ani podtriedu Promise.
Nie
Nemôžete, aby vaša findBarWithFooName vrátila dotaz akokoľvek, pretože musí počkať na Foo.findOne, kým sa vôbec zavolá Bar.find a nevytvorí objekt Query, ktorý hľadáte.
Aby ste vyriešili svoj problém, budete musieť vrátiť nejaký wrapper pre dotaz - nemôžete return dotaz priamo, pretože je thenable a je implicitne očakávaný. Volanie by potom vyzeralo takto
let bars = await ( unwrap(await Bar.findBarWithFooName('fooName')).sort('date') );
s unwrap ako niečím, čo vezme Query z obalu. Ako obal môžete použiť čokoľvek bez metódy then - môže to byť uzávierka, objekt s vlastnosťou, pole s jedným prvkom…
