MongoDB、Mongoose 和 Apollo GraphQL 在文档中定义 _id 类型

Posted

技术标签:

【中文标题】MongoDB、Mongoose 和 Apollo GraphQL 在文档中定义 _id 类型【英文标题】:MongoDB, Mongoose and Apollo GraphQL defining _id type in document 【发布时间】:2019-07-31 10:14:23 【问题描述】:

我在这个项目中使用 TypeScript 和 NestJS:

https://github.com/EricKit/nest-user-auth

我正在尝试将 _id 属性添加到 GraphQL Schema:

type User 
  username: String!
  email: String!
  permissions: [String!]!
  createdAt: Date!
  updatedAt: Date!
  enabled: Boolean!
  _id: String!

现在,NestJS 从这个模式为用户生成一个类型文件

export abstract class User 
    username: string;
    email: string;
    permissions: string[];
    createdAt: Date;
    updatedAt: Date;
    enabled: boolean;
    _id: string;

现在的问题是我想为 UserDocument 创建一个接口,添加 mongoDB 特定字段并定义一个文档

export interface UserDocument extends User, Document 
  // Declaring everything that is not in the GraphQL Schema for a User
  _id: string; // TODO: This should actually be Types.ObjectId
  password: string;
  lowercaseUsername: string;
  lowercaseEmail: string;
  passwordReset?: 
    token: string;
    expiration: Date;
  ;

  checkPassword(password: string): Promise<boolean>;

我无法将 _id 定义为 mongoose.Type.ObjectID,因为它会产生错误:

Interface 'UserDocument' incorrectly extends interface 'User'.
  Types of property '_id' are incompatible.
    Type 'ObjectId' is not assignable to type 'string'.

这是有道理的,我想找到一种方法将其作为 ObjectId 保存在我的 UserDocument 架构中,将其保存为架构中的字符串,并且仍然能够扩展 GraphQL 架构类型。这可能吗?

【问题讨论】:

【参考方案1】:

GraphQL 方式是用于序列化/反序列化 ObjectId 的自定义标量类型

GraphQL 架构

scalar Date
scalar MongoObjectId
...
type User 
  username: String!
  email: String!
  permissions: [String!]!
  createdAt: Date!
  updatedAt: Date!
  enabled: Boolean!
  _id: MongoObjectId!

MongoObjectId 标量类,灵感来自 NestJs Date scalar 和 TypeGraphQL ObjectId scalar

import  Scalar  from '@nestjs/graphql';
import  Kind, ASTNode  from 'graphql';
import  ObjectId  from "mongodb";

@Scalar('MongoObjectId')
export class ObjectIdScalar 
  description = 'Mongo object id scalar type';

  parseValue(value: string) 
    return new ObjectId(value); // value from the client
  

  serialize(value: ObjectId) 
    return value.toHexString(); // value sent to the client
  

  parseLiteral(ast: ASTNode) 
    if (ast.kind === Kind.STRING) 
      return new ObjectId(ast.value); // value from the client query
    
    return null;
  

之后,我们需要将ObjectIdScalar注册为提供者(就像date scalar一样)并将_idstring更改为Type.ObjectID

【讨论】:

fwiw, there's already a lib available 如果您不想创建自己的标量 MongoDb 和 Mongoose Types.ObjectId 有什么区别? 不。 Mongoose 重新导入 ObjectId。

以上是关于MongoDB、Mongoose 和 Apollo GraphQL 在文档中定义 _id 类型的主要内容,如果未能解决你的问题,请参考以下文章

使用 Apollo-GraphQL、MongoDB-Mongoose 和 Node-Express 构建的 React 应用程序在生产构建中返回 404 错误

我无法使用 mongo / mongoose / NO METEOR 设置 react apollo mongodb app => 解析器

Apollo Angular 无法从 GraphQL/MongoDB 获取数据

从上下文中获取模型与导入 - apollo server express & mongoose

返回突变结果的正确方法? (GraphQL 与 Apollo 和 Mongoose

Mongoose 在 Apollo-Express 服务器上抛出错误 ECONNREFUSED