Почему findOneAndRemove иногда передает null для выполнения c в обратном вызове? - PullRequest
0 голосов
/ 29 марта 2020

Я использую следующую функцию, которая должна иметь входной сигнал обратного вызова: https://mongoosejs.com/docs/api.html#model_Model .findOneAndRemove

У меня есть следующий объект мутации, который должен удалить конкретное лекарство из базу данных, а затем удалите все экземпляры ее 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 успешно удаляет документ с args.id в коллекции Medicine, но когда он вызывает функцию обратного вызова, иногда он пропускает null для выполнения c, поэтому функция обратного вызова не всегда выполнить правильно.

Кроме того, я получаю необработанное предупреждение об ошибке, хотя я перехватываю все ошибки. \

Я добавил logi c для обработки, когда err и do c оба равны нулю согласно этому сообщению: https://github.com/Automattic/mongoose/issues/5022

1 Ответ

0 голосов
/ 29 марта 2020

Вы должны использовать только обещания, а не обратные вызовы, с GraphQL. js. Если используемая вами библиотека не поддерживает Promises, вам нужно обернуть каждый обратный вызов в 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
}

Обычно при работе с Promises мы используем метод catch (или try / catch с async / await) для обработки ошибок. Однако это только необходимо внутри распознавателя, если вы хотите замаскировать или иным образом отформатировать свою ошибку - в противном случае GraphQL с радостью обнаружит любые ошибки и вернет их в ответ. Однако это работает только в том случае, если ваши Обещания правильно соединены в цепочку, и распознаватель возвращает Обещание. Если в конечном итоге вы получите «сиротское» обещание, которого не ожидаете, вы увидите необработанные предупреждения об ошибках.

...