Вопрос или проблема
Я использую Typegoose с mongoose-autopopulate и пытаюсь вернуть заполненную модель внутри моего резолвера. Однако я получаю ошибку Ref<SomeReference> не может быть присвоен SomeReference>, отсутствует _id, name...
.
Кроме как сделать поле ссылки объектом вместо ObjectID, есть ли какие-либо возможные обходные пути для этого? Спасибо.
Куски кода
Модели Mongoose:
@plugin(autopopulate as any)
export class Collection extends TimeStamps {
@prop()
public name!: string;
@prop({ autopopulate: true, ref: () => SomeReference })
public link?: Ref<SomeReference>;
}
export class SomeReference extends TimeStamps {
@prop()
public name!: string;
}
Схема GraphQL (я использую schema-first в NestJS):
type Collection {
_id: ID!
name: String!
link: SomeReference
}
Метод резолвера:
private toPopulatedField(collection: CollectionDocument): Collection {
return {
_id: collection._id.toString(),
name: collection.name,
// link: {
// _id: collection.link._id.toString(),
// name: collection.link.name, --> ошибка: имя не существует в ObjectID
// },
};
}
Ответ или решение
Чтобы сопоставить пополненные модели Mongoose с созданными типами GraphQL в NestJS, вам необходимо правильно обрабатывать возвращаемые данные и убедиться, что типы ваших полей соответствуют ожидаемым GraphQL типам. Давайте разберёмся с вашей проблемой, основываясь на предоставленных вами кодах.
Проблема
Ошибка, с которой вы столкнулись, связана с тем, что поле link
в вашем классе Collection
имеет тип Ref<SomeReference>
, но GraphQL ожидает, что это будет объект типа SomeReference
. При этом, если link
не был инициализирован (т.е. равно null
или undefined
), попытка доступа к collection.link._id
и collection.link.name
приведет к ошибке, потому что вы пытаетесь получить доступ к свойствам объекта, который не существует.
Решение
-
Изменение метода сопоставления: Убедитесь, что перед тем, как извлекать свойства
link
, вы проверяете, что он существует. Если объект ссылки существует, вы можете безопасно получить его свойства. - Корректное определение типов: Убедитесь, что в GraphQL определены все возможные типы, которые вы можете вернуть. В этом случае ваш
SomeReference
должен корректно определять все поля, которые вы хотите вернуть.
Вот исправленный пример вашего кода:
// Модель Mongoose
@plugin(autopopulate as any)
export class Collection extends TimeStamps {
@prop()
public name!: string;
@prop({ autopopulate: true, ref: () => SomeReference })
public link?: Ref<SomeReference>;
}
export class SomeReference extends TimeStamps {
@prop()
public name!: string;
}
// GraphQL схема (schema-first подход)
type Collection {
_id: ID!
name: String!
link: SomeReference
}
// Модифицированный метод резолвера
private toPopulatedField(collection: CollectionDocument): Collection {
return {
_id: collection._id.toString(),
name: collection.name,
link: collection.link ? {
_id: collection.link._id.toString(),
name: collection.link.name
} : null, // Проверяем, существует ли ссылка
};
}
Дополнительные рекомендации
-
Проверка на null и undefined: Всегда полезно проверять, существует ли объект перед доступом к его свойствам, чтобы избежать ошибок выполнения.
-
Убедитесь, что Mongoose правильно находит и заполняет объекты: Если вы используете
mongoose-autopopulate
, убедитесь, что связи между коллекциями определены корректно, и Mongoose знает, как их заполнять. - Логирование: В процессе отладки может быть полезно использовать логирование, чтобы видеть, какие поля возвращаются на каждом уровне.
Заключение
Следуя приведенным выше рекомендациям и упрощая ваш метод маппинга, вы сможете правильно сопоставить свои модели Mongoose с типами GraphQL в NestJS. Это поможет избежать ошибок типизации и обеспечит, чтобы данные возвращались в ожидаемом формате.