【问题标题】:Why is findOneAndRemove sometimes passing null to doc in the callback?为什么 findOneAndRemove 有时会在回调中将 null 传递给 doc?
【发布时间】:2020-07-09 14:30:00
【问题描述】:

我正在使用以下应该具有回调输入的函数: https://mongoosejs.com/docs/api.html#model_Model.findOneAndRemove

我有以下 Mutation 对象,该对象应该从数据库中删除特定药物,然后从包含该 ID 的所有 Day 条目的数组中删除其 MedicineId 的所有实例。

 deleteMedicine: {
            type: MedicineType,
            args: {
                id: { type: new GraphQLNonNull(GraphQLID) }
            },

            async resolve (parent, args) {

                let res = Medicine.findOneAndRemove({ _id: args.id }, async (err, doc) => {

                    if (err === null && doc === null || doc === null) {
                        return;
                    } else if (err) {
                        console.error(err);
                        return;
                    } else {
                        return await Promise.all(doc.dayNames.map(dayName => {
                            return DayOfWeek.findByIdAndUpdate(dayName, { $pull: { medicineIds: doc._id }})
                            .catch((error1) => console.error(error1));
                        })).catch((error2) => console.error(error2)); 
                    }
                });

                await res; 
                return res; 
            }
        }

findOneAndRemove 成功删除 Medicine 集合中具有 args.id 的文档,但是当它调用回调函数时,有时会将 null 传递给 doc,因此回调函数无法始终正确执行。

即使我发现了所有错误,我也会收到未处理的错误警告。 \

根据这篇文章,当 err 和 doc 都为空时,我添加了处理逻辑: https://github.com/Automattic/mongoose/issues/5022

【问题讨论】:

  • 你找到解决办法了吗?我对findByIdAndDelete() 也有同样的问题。文档已从数据库中删除,但回调在文档中返回 null。

标签: javascript node.js async-await graphql-js


【解决方案1】:

您应该只对 GraphQL.js 使用 Promises,而不是回调。如果你使用的库不支持 Promises,那么你需要wrap each callback in a Promise。然而,mongoose 有很好的 Promise 支持——你只需在方法调用中省略回调,调用就会返回一个 Promise。

为了避免在使用 Promises 时出现“回调地狱”以及正确链接 Promises 的问题,通常最好使用 async/await 语法。清理后的解析器看起来像:

async resolve (parent, args) {
  // Omit the callback to get a Promise and then await the result
  const medicine = await Medicine.findOneAndRemove({ _id: args.id })

  // If a medicine with that ID couldn't be found, we'll get a null
  if (medicine) {
    // Make sure we await the Promise returned by Promise.all 
    await Promise.all(doc.dayNames.map(dayName => DayOfWeek.findByIdAndUpdate(
      dayName,
      { $pull: { medicineIds: doc._id } }
    ))
  }

  // Make sure we return the appropriate result depending on the field's type
  return medicine
}

通常在处理 Promise 时,我们使用 catch 方法(或 try/catch 与 async/await)来处理错误。但是,如果您想屏蔽或以其他方式格式化您的错误,这在解析器中是必需的 - 否则,GraphQL 会很乐意为您捕获任何错误并在响应中返回它们。但是,这仅在您的 Promises 正确链接并且解析器返回 Promise 时才有效。如果您最终得到一个未等待的“孤儿” Promise,您将看到未处理的错误警告。

【讨论】:

    猜你喜欢
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多