是否可以使异步函数返回mongoose Query而不是Promise?

时间:2017-09-06 01:10:07

标签: javascript node.js typescript mongoose async-await

设置

我们假设我们有一些文件FooBarFoo有一个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);

现在假设我们有nameFoo文档,但不是_id。我们希望查找引用Bar文档的所有Foo文档。因此,我们编写一个函数,首先找到具有给定Foo的{​​{1}}文档,然后使用它来查找name文档。

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'); 进行排序。通常,使用mongoose的“查询”构建器,我们可以编写如下内容:

bars

但是,如果我们改为使用我们写的函数:

let bars = await Bar.find({})
                    .sort('date');

我们会收到错误:

  

UnhandledPromiseRejectionWarning:未处理的承诺   rejection(拒绝id:1):TypeError:   Bar.findBarWithFooName(...)。sort不是函数

调试

在调查let bars = await Bar.findBarWithFooName('fooName') .sort('date'); 时,我发现当我们调用console.log(bars)时,生成的对象是猫鼬的Bar.find({})对象。

但是,当我们调用Query时,生成的对象为Bar.findBarWithFooName('fooName')。因此,Promise { <pending> }上的sort方法不存在是有道理的。

问题

我的问题是,为什么在第一种情况下,它会返回Promise { <pending> },但在第二种情况下,它会返回Query?我可以做些什么让Promise { <pending> }返回findBarWithFooName,以便我可以继续构建查询,而不是Query

我知道我可以使用的一个解决方案是从Promise { <pending> }中取出await Foo.findOne({ name: name }),只需将findBarWithFooName作为参数而不是_id。但是,我试图抽象出必须首先找到name的过程,这就是我尝试创建一个返回Foo的函数的原因。

1 个答案:

答案 0 :(得分:2)

不可能让async function返回自定义对象而不是Promise - 甚至不是promise子类。

您无法让findBarWithFooName返回查询,因为在Foo.findOne被调用之前必须等待Bar.find并构建您正在查找的查询对象。

要解决您的问题,您需要为查询返回一些包装器 - 您不能直接return查询,因为它可以直接查询并且会被隐式等待。然后呼叫看起来像

let bars = await ( unwrap(await Bar.findBarWithFooName('fooName')).sort('date') );

unwrap是将查询从包装器中取出的东西。作为包装器,您可以使用没有then方法的任何东西 - 它可以是闭包,具有属性的对象,具有单个元素的数组......