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

Die*_*sel 2 mongoose mongodb node.js graphql nestjs

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

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

我正在尝试将 _id 属性添加到 GraphQL 架构中:

type User {
  username: String!
  email: String!
  permissions: [String!]!
  createdAt: Date!
  updatedAt: Date!
  enabled: Boolean!
  _id: String!
}
Run Code Online (Sandbox Code Playgroud)

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

export abstract class User {
    username: string;
    email: string;
    permissions: string[];
    createdAt: Date;
    updatedAt: Date;
    enabled: boolean;
    _id: string;
}
Run Code Online (Sandbox Code Playgroud)

现在的问题是我想为 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>;
}
Run Code Online (Sandbox Code Playgroud)

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

Interface 'UserDocument' incorrectly extends interface 'User'.
  Types of property '_id' are incompatible.
    Type 'ObjectId' is not assignable to type 'string'.
Run Code Online (Sandbox Code Playgroud)

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

gal*_*kin 5

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

GraphQL 架构

scalar Date
scalar MongoObjectId
...
type User {
  username: String!
  email: String!
  permissions: [String!]!
  createdAt: Date!
  updatedAt: Date!
  enabled: Boolean!
  _id: MongoObjectId!
}
Run Code Online (Sandbox Code Playgroud)

MongoObjectId 标量类,受到NestJs Date 标量TypeGraphQL ObjectId 标量的启发

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

之后,我们需要注册为提供者(就像日期标量ObjectIdScalar一样)并从更改为。_idstringType.ObjectID

  • fwiw,如果您不想创建自己的标量,[已经有一个可用的库](https://github.com/isayme/graphql-scalar-objectid) (2认同)