是否有可能使一个asynchronous函数返回一个mongoose查询而不是一个承诺?
build立
假设我们有一些文件Foo
和Bar
。 Foo
有一个name
字段,可以用来识别除了使用文档_id
以外的其他文档。 Bar
包含对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);
现在假设我们有一个Foo
文件的name
,但不是它的_id
。 我们想find所有引用Foo
文档的Bar
文档。 所以我们编写一个函数,首先find具有给定name
的Foo
文档,然后使用它来查找Bar
文档。
barSchema.statics.findBarWithFooName = async function(name: string) { let foo = await Foo.findOne({ name: name }); return Bar.find({ foo: foo }); };
我们可以使用这个函数写:
let bars = await Bar.findBarWithFooName('fooName');
问题
不过,我们也想按datesortingbars
。 通常,使用mongoose的查询生成器,我们可以这样写:
let bars = await Bar.find({}) .sort('date');
但是,如果我们使用我们写的函数:
let bars = await Bar.findBarWithFooName('fooName') .sort('date');
我们会得到一个错误:
UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝id:1):TypeError:Bar.findBarWithFooName(…)。sort不是一个函数
debugging
通过调查console.log(bars)
,我发现当我们调用Bar.find({})
,生成的对象是mongoose的Query
对象。
但是,当我们调用Bar.findBarWithFooName('fooName')
,生成的对象是Promise { <pending> }
。 因此,在Promise { <pending> }
上不存在方法sort
是有意义的。
题
那么我的问题是,为什么在第一种情况下,它返回一个Query
,但在第二种情况下,它返回一个Promise { <pending> }
? 我能做些什么来使findBarWithFooName
返回一个Query
以便我可以继续构build查询,而不是Promise { <pending> }
?
我知道我可以使用的一个解决scheme是从await Foo.findOne({ name: name })
取出await Foo.findOne({ name: name })
,只需要一个_id
作为参数而不是name
。 但是,我试图抽象出先find一个Foo
的过程,这就是为什么我要创build一个返回Query
的单个函数。
没有
使一个async function
返回一个自定义对象而不是一个Promise
是不可能的 – 甚至不是一个promise子类。
没有
你不能让findBarWithFooName
返回一个查询,因为在Bar.find
被调用之前它必须等待Foo.findOne
,并构造你正在查找的Query对象。
为了解决你的问题,你将需要返回一些包装的查询 – 你不能直接return
查询,因为它是可以的,并得到隐含等待。 电话会看起来像
let bars = await ( unwrap(await Bar.findBarWithFooName('fooName')).sort('date') );
unwrap
是将Query从包装中取出的东西。 作为一个包装,你可以使用任何东西,而无需使用then
方法 – 它可以是一个闭包,一个具有属性的对象,一个具有单个元素的数组。