พังพอนทาง typescript …?


94

กำลังพยายามใช้แบบจำลองพังพอนใน typescript การกำจัดสิ่งสกปรกใน Google ได้เปิดเผยเฉพาะแนวทางแบบผสมผสาน (รวม JS และ TS) เราจะดำเนินการอย่างไรเกี่ยวกับการใช้คลาส User บนแนวทางที่ค่อนข้างไร้เดียงสาของฉันโดยไม่มี JS?

ต้องการ IUserModel โดยไม่ต้องมีสัมภาระ

import {IUser} from './user.ts';
import {Document, Schema, Model} from 'mongoose';

// mixing in a couple of interfaces
interface IUserDocument extends IUser,  Document {}

// mongoose, why oh why '[String]' 
// TODO: investigate out why mongoose needs its own data types
let userSchema: Schema = new Schema({
  userName  : String,
  password  : String,
  firstName : String,
  lastName  : String,
  email     : String,
  activated : Boolean,
  roles     : [String]
});

// interface we want to code to?
export interface IUserModel extends Model<IUserDocument> {/* any custom methods here */}

// stumped here
export class User {
  constructor() {}
}

Userไม่สามารถเป็นคลาสได้เนื่องจากการสร้างคลาสเป็นการดำเนินการแบบ async มันต้องคืนคำสัญญาดังนั้นคุณต้องโทรUser.create({...}).then....
Louay Alakkad

1
โดยเฉพาะระบุไว้ในรหัสใน OP คุณช่วยอธิบายให้ละเอียดUserได้ไหมว่าทำไมไม่สามารถเป็นคลาสได้
Tim McNamara

ลองใช้github.com/typeorm/typeormแทน
Erich

@ พวกเขาบอกว่า typeorm ใช้ไม่ได้กับ MongoDB บางที Type goose ก็เป็นตัวเลือกที่ดี
PayamBeirami

ลองดูที่npmjs.com/package/@types/mongoose
Harry

คำตอบ:


133

นี่คือวิธีการ:

export interface IUser extends mongoose.Document {
  name: string; 
  somethingElse?: number; 
};

export const UserSchema = new mongoose.Schema({
  name: {type:String, required: true},
  somethingElse: Number,
});

const User = mongoose.model<IUser>('User', UserSchema);
export default User;

2
ขอโทษที แต่คำว่า 'พังพอน' ถูกกำหนดใน TS อย่างไร?
Tim McNamara

13
import * as mongoose from 'mongoose';หรือimport mongoose = require('mongoose');
Louay Alakkad

1
สิ่งนี้:import User from '~/models/user'; User.find(/*...*/).then(/*...*/);
Louay Alakkad

3
บรรทัดสุดท้าย (ส่งออกค่าเริ่มต้นผู้ใช้ ... ) ไม่ทำงานสำหรับฉัน ฉันต้องแยกบรรทัดตามที่เสนอในstackoverflow.com/questions/35821614/…
Sergio

7
ฉันสามารถทำได้let newUser = new User({ iAmNotHere: true })โดยไม่มีข้อผิดพลาดใด ๆ ใน IDE หรือในการคอมไพล์ แล้วเหตุผลในการสร้างอินเทอร์เฟซคืออะไร?
Lupurus

34

อีกทางเลือกหนึ่งหากคุณต้องการแยกข้อกำหนดประเภทและการนำฐานข้อมูลออก

import {IUser} from './user.ts';
import * as mongoose from 'mongoose';

type UserType = IUser & mongoose.Document;
const User = mongoose.model<UserType>('User', new mongoose.Schema({
    userName  : String,
    password  : String,
    /* etc */
}));

แรงบันดาลใจจากที่นี่: https://github.com/Appsilon/styleguide/wiki/mongoose-typescript-models


1
ที่ไม่mongoose.Schemaนิยามที่นี่ซ้ำสาขาจากIUser? ระบุว่าIUserมีการกำหนดไว้ในแฟ้มที่แตกต่างความเสี่ยงว่าเขตข้อมูลที่มีได้รับการออกจากซิงค์เป็นโครงการที่เติบโตขึ้นในความซับซ้อนและจำนวนนักพัฒนาค่อนข้างสูง
Dan Dascalescu

ใช่นี่เป็นข้อโต้แย้งที่ถูกต้องซึ่งควรค่าแก่การพิจารณา การใช้การทดสอบการรวมส่วนประกอบอาจช่วยลดความเสี่ยงได้ และโปรดทราบว่ามีแนวทางและสถาปัตยกรรมที่แยกการประกาศประเภทและการใช้งาน DB ไม่ว่าจะทำผ่าน ORM (ตามที่คุณเสนอ) หรือด้วยตนเอง (เช่นในคำตอบนี้) ไม่มีกระสุนเงิน ... <(°. °)>
Gábor Imre

สัญลักษณ์แสดงหัวข้อย่อยหนึ่งรายการอาจเป็นการสร้างโค้ดจากนิยาม GraphQL สำหรับ TypeScript และพังพอน
Dan Dascalescu

24

ขออภัยสำหรับการเนโครโพสต์ แต่สิ่งนี้ยังน่าสนใจสำหรับใครบางคน ฉันคิดว่าTypegooseให้วิธีที่ทันสมัยและสง่างามกว่าในการกำหนดโมเดล

นี่คือตัวอย่างจากเอกสาร:

import { prop, Typegoose, ModelType, InstanceType } from 'typegoose';
import * as mongoose from 'mongoose';

mongoose.connect('mongodb://localhost:27017/test');

class User extends Typegoose {
    @prop()
    name?: string;
}

const UserModel = new User().getModelForClass(User);

// UserModel is a regular Mongoose Model with correct types
(async () => {
    const u = new UserModel({ name: 'JohnDoe' });
    await u.save();
    const user = await UserModel.findOne();

    // prints { _id: 59218f686409d670a97e53e0, name: 'JohnDoe', __v: 0 }
    console.log(user);
})();

สำหรับสถานการณ์การเชื่อมต่อที่มีอยู่คุณสามารถใช้สิ่งต่อไปนี้ (ซึ่งอาจเป็นไปได้มากกว่าในสถานการณ์จริงและเปิดเผยในเอกสาร):

import { prop, Typegoose, ModelType, InstanceType } from 'typegoose';
import * as mongoose from 'mongoose';

const conn = mongoose.createConnection('mongodb://localhost:27017/test');

class User extends Typegoose {
    @prop()
    name?: string;
}

// Notice that the collection name will be 'users':
const UserModel = new User().getModelForClass(User, {existingConnection: conn});

// UserModel is a regular Mongoose Model with correct types
(async () => {
    const u = new UserModel({ name: 'JohnDoe' });
    await u.save();
    const user = await UserModel.findOne();

    // prints { _id: 59218f686409d670a97e53e0, name: 'JohnDoe', __v: 0 }
    console.log(user);
})();

8
ฉันได้ข้อสรุปนี้เช่นกัน แต่ฉันกังวลว่าtypegooseไม่มีการสนับสนุนเพียงพอ ... ตรวจสอบสถิติ npm ของพวกเขามีการดาวน์โหลดเพียง 3k ต่อสัปดาห์และ rn มีปัญหา Github ที่เปิดอยู่เกือบ 100 รายการซึ่งส่วนใหญ่ไม่มีความคิดเห็น และบางแห่งดูเหมือนว่าควรจะปิดไปนานแล้ว
Corbfon

@Corbfon ลองรึยัง? ถ้าเป็นเช่นนั้นสิ่งที่คุณค้นพบคืออะไร? ถ้าไม่มีมีอะไรอีกไหมที่ทำให้คุณตัดสินใจไม่ใช้มัน? ฉันมักจะเห็นบางคนกังวลเกี่ยวกับการสนับสนุนที่สมบูรณ์ แต่ดูเหมือนว่าผู้ที่ใช้งานจริงจะค่อนข้างพอใจกับมัน
N4ppeL

1
@ N4ppeL ฉันจะไม่ไปด้วยtypegoose- เราลงเอยด้วยการจัดการการพิมพ์ของเราด้วยตนเองคล้ายกับโพสต์นี้ดูเหมือนว่าts-mongooseอาจมีสัญญาบางอย่าง (ตามที่แนะนำในคำตอบในภายหลัง)
Corbfon

1
อย่าขอโทษสำหรับ "necroposting" [อย่างที่คุณรู้แล้ว ... ] ยังมีตรา (แม้ว่ามันจะชื่อเนโคแมนเซอร์ก็ตาม ^ D) สำหรับการทำสิ่งนี้! Necroposting ข้อมูลและแนวคิดใหม่ ๆ ได้รับการสนับสนุน!
ruffin

1
@ruffin: ฉันยังไม่เข้าใจความอัปยศจากการโพสต์วิธีแก้ปัญหาใหม่ ๆ และเป็นปัจจุบัน
Dan Dascalescu

16

ลองts-mongoose. ใช้ชนิดเงื่อนไขในการทำแผนที่

import { createSchema, Type, typedModel } from 'ts-mongoose';

const UserSchema = createSchema({
  username: Type.string(),
  email: Type.string(),
});

const User = typedModel('User', UserSchema);

1
น่าดูมาก! ขอบคุณสำหรับการแบ่งปัน! :)
Boriel

1
ว้าว. ล็อคนี้เก๋ไก๋มาก รอคอยที่จะลอง!
qqilihq

1
การเปิดเผยข้อมูล: ts-mongoose ดูเหมือนจะถูกสร้างขึ้นโดยท้องฟ้า ดูเหมือนจะเป็นวิธีแก้ปัญหาที่เนียนที่สุด
ไมค์

1
แพ็คเกจสวยดียังดูแลรักษาอยู่ไหม
Dan Dascalescu

11

คำตอบส่วนใหญ่ที่นี่จะทำซ้ำฟิลด์ในคลาส / อินเตอร์เฟส TypeScript และในสคีมาพังพอน การไม่มีแหล่งความจริงเพียงแหล่งเดียวแสดงถึงความเสี่ยงในการบำรุงรักษาเนื่องจากโครงการมีความซับซ้อนมากขึ้นและมีนักพัฒนาทำงานมากขึ้น: ช่องต่างๆมีแนวโน้มที่จะไม่ซิงค์กัน สิ่งนี้ไม่ดีอย่างยิ่งเมื่อคลาสอยู่ในไฟล์อื่นเทียบกับสคีมาพังพอน

หากต้องการให้ช่องข้อมูลตรงกันคุณควรกำหนดครั้งเดียว มีห้องสมุดสองสามแห่งที่ทำสิ่งนี้:

ฉันยังไม่ได้รับความเชื่อมั่นอย่างเต็มที่จากพวกเขา แต่ typegoose ดูเหมือนได้รับการดูแลอย่างแข็งขันและนักพัฒนายอมรับการประชาสัมพันธ์ของฉัน

ในการคิดล่วงหน้าหนึ่งก้าว: เมื่อคุณเพิ่มสคีมา GraphQL ลงในส่วนผสมการทำสำเนาโมเดลอีกชั้นจะปรากฏขึ้น วิธีหนึ่งในการแก้ไขปัญหานี้คือการสร้าง TypeScript และโค้ดพังพอนจากสคีมา GraphQL


5

นี่เป็นวิธีการพิมพ์ที่ชัดเจนในการจับคู่โมเดลธรรมดากับสคีมาพังพอน คอมไพเลอร์จะตรวจสอบให้แน่ใจว่าคำจำกัดความที่ส่งผ่านไปยังพังพอนสคีมาตรงกับอินเทอร์เฟซ เมื่อคุณมีสคีมาแล้วคุณสามารถใช้

common.ts

export type IsRequired<T> =
  undefined extends T
  ? false
  : true;

export type FieldType<T> =
  T extends number ? typeof Number :
  T extends string ? typeof String :
  Object;

export type Field<T> = {
  type: FieldType<T>,
  required: IsRequired<T>,
  enum?: Array<T>
};

export type ModelDefinition<M> = {
  [P in keyof M]-?:
    M[P] extends Array<infer U> ? Array<Field<U>> :
    Field<M[P]>
};

user.ts

import * as mongoose from 'mongoose';
import { ModelDefinition } from "./common";

interface User {
  userName  : string,
  password  : string,
  firstName : string,
  lastName  : string,
  email     : string,
  activated : boolean,
  roles     : Array<string>
}

// The typings above expect the more verbose type definitions,
// but this has the benefit of being able to match required
// and optional fields with the corresponding definition.
// TBD: There may be a way to support both types.
const definition: ModelDefinition<User> = {
  userName  : { type: String, required: true },
  password  : { type: String, required: true },
  firstName : { type: String, required: true },
  lastName  : { type: String, required: true },
  email     : { type: String, required: true },
  activated : { type: Boolean, required: true },
  roles     : [ { type: String, required: true } ]
};

const schema = new mongoose.Schema(
  definition
);

เมื่อคุณมีสคีมาแล้วคุณสามารถใช้วิธีการที่กล่าวถึงในคำตอบอื่น ๆ เช่น

const userModel = mongoose.model<User & mongoose.Document>('User', schema);

1
นี่เป็นคำตอบเดียวที่ถูกต้อง ไม่มีคำตอบอื่นใดที่รับประกันความเข้ากันได้ของประเภทระหว่างสคีมาและประเภท / อินเทอร์เฟซ
Jamie Strauss


1
@DanDascalescu ฉันไม่คิดว่าคุณจะเข้าใจวิธีการทำงานของประเภท
Jamie Strauss

5

เพิ่มวิธีอื่น ( @types/mongooseต้องติดตั้งด้วยnpm install --save-dev @types/mongoose)

import { IUser } from './user.ts';
import * as mongoose from 'mongoose';

interface IUserModel extends IUser, mongoose.Document {}

const User = mongoose.model<IUserModel>('User', new mongoose.Schema({
    userName: String,
    password: String,
    // ...
}));

และความแตกต่างระหว่างinterfaceและtypeโปรดอ่านคำตอบนี้

วิธีนี้มีข้อได้เปรียบคุณสามารถเพิ่มวิธีการพิมพ์แบบคงที่ของพังพอน:

interface IUserModel extends IUser, mongoose.Document {
  generateJwt: () => string
}

คุณกำหนดgenerateJwtที่ไหน
rels

1
@rels const User = mongoose.model.... password: String, generateJwt: () => { return someJwt; } }));โดยพื้นฐานแล้วgenerateJwtจะกลายเป็นคุณสมบัติอื่นของโมเดล
a11smiles

คุณจะเพิ่มเป็นวิธีการในลักษณะนี้หรือคุณจะเชื่อมต่อกับคุณสมบัติวิธีการ?
user1790300

1
นี่ควรเป็นคำตอบที่ยอมรับได้เนื่องจากแยกนิยามผู้ใช้และผู้ใช้ DAL หากคุณต้องการเปลี่ยนจาก mongo ไปเป็นผู้ให้บริการฐานข้อมูลรายอื่นคุณไม่จำเป็นต้องเปลี่ยนอินเทอร์เฟซผู้ใช้
Rafael del Rio

1
@RafaeldelRio: คำถามเกี่ยวกับการใช้พังพอนกับ TypeScript การเปลี่ยนไปใช้ฐานข้อมูลอื่นเป็นสิ่งที่ตรงกันข้ามกับเป้าหมายนี้ และปัญหาในการแยกข้อกำหนดสคีมาออกจากการIUserประกาศอินเทอร์เฟซในไฟล์อื่นก็คือความเสี่ยงที่ช่องจะไม่ซิงค์กันเมื่อโปรเจ็กต์มีจำนวนความซับซ้อนและนักพัฒนาเพิ่มขึ้นค่อนข้างสูง
Dan Dascalescu

4

นี่คือวิธีที่ผู้ชายใน Microsoft ทำ ที่นี่

import mongoose from "mongoose";

export type UserDocument = mongoose.Document & {
    email: string;
    password: string;
    passwordResetToken: string;
    passwordResetExpires: Date;
...
};

const userSchema = new mongoose.Schema({
    email: { type: String, unique: true },
    password: String,
    passwordResetToken: String,
    passwordResetExpires: Date,
...
}, { timestamps: true });

export const User = mongoose.model<UserDocument>("User", userSchema);

ฉันขอแนะนำให้ตรวจสอบโครงการเริ่มต้นที่ยอดเยี่ยมนี้เมื่อคุณเพิ่ม TypeScript ลงในโครงการ Node ของคุณ

https://github.com/microsoft/TypeScript-Node-Starter


1
การทำซ้ำทุกช่องระหว่างพังพอนและ TypeScript ซึ่งจะสร้างความเสี่ยงในการบำรุงรักษาเนื่องจากโมเดลมีความซับซ้อนมากขึ้น วิธีแก้ปัญหาเช่นเดียวกับts-mongooseและtypegooseแก้ปัญหานั้นแม้ว่าจะเป็นที่ยอมรับโดยมีข้อบกพร่องทางวากยสัมพันธ์เล็กน้อย
Dan Dascalescu

2

ด้วยการvscode intellisenseทำงานนี้กับทั้งสองอย่าง

  • ประเภทผู้ใช้ User.findOne
  • อินสแตนซ์ผู้ใช้ u1._id

รหัส:

// imports
import { ObjectID } from 'mongodb'
import { Document, model, Schema, SchemaDefinition } from 'mongoose'

import { authSchema, IAuthSchema } from './userAuth'

// the model

export interface IUser {
  _id: ObjectID, // !WARNING: No default value in Schema
  auth: IAuthSchema
}

// IUser will act like it is a Schema, it is more common to use this
// For example you can use this type at passport.serialize
export type IUserSchema = IUser & SchemaDefinition
// IUser will act like it is a Document
export type IUserDocument = IUser & Document

export const userSchema = new Schema<IUserSchema>({
  auth: {
    required: true,
    type: authSchema,
  }
})

export default model<IUserDocument>('user', userSchema)


2

นี่คือตัวอย่างจากเอกสาร Mongoose การสร้างจากคลาส ES6 โดยใช้ loadClass ()แปลงเป็น TypeScript:

import { Document, Schema, Model, model } from 'mongoose';
import * as assert from 'assert';

const schema = new Schema<IPerson>({ firstName: String, lastName: String });

export interface IPerson extends Document {
  firstName: string;
  lastName: string;
  fullName: string;
}

class PersonClass extends Model {
  firstName!: string;
  lastName!: string;

  // `fullName` becomes a virtual
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  set fullName(v) {
    const firstSpace = v.indexOf(' ');
    this.firstName = v.split(' ')[0];
    this.lastName = firstSpace === -1 ? '' : v.substr(firstSpace + 1);
  }

  // `getFullName()` becomes a document method
  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  // `findByFullName()` becomes a static
  static findByFullName(name: string) {
    const firstSpace = name.indexOf(' ');
    const firstName = name.split(' ')[0];
    const lastName = firstSpace === -1 ? '' : name.substr(firstSpace + 1);
    return this.findOne({ firstName, lastName });
  }
}

schema.loadClass(PersonClass);
const Person = model<IPerson>('Person', schema);

(async () => {
  let doc = await Person.create({ firstName: 'Jon', lastName: 'Snow' });
  assert.equal(doc.fullName, 'Jon Snow');
  doc.fullName = 'Jon Stark';
  assert.equal(doc.firstName, 'Jon');
  assert.equal(doc.lastName, 'Stark');

  doc = (<any>Person).findByFullName('Jon Snow');
  assert.equal(doc.fullName, 'Jon Snow');
})();

สำหรับfindByFullNameวิธีการคงที่ฉันคิดไม่ออกว่าจะรับข้อมูลประเภทPersonอย่างไรดังนั้นฉันจึงต้องส่ง<any>Personเมื่อฉันต้องการเรียกมัน หากคุณทราบวิธีแก้ไขโปรดเพิ่มความคิดเห็น


เช่นเดียวกับคำตอบอื่น ๆวิธีนี้ซ้ำช่องระหว่างอินเทอร์เฟซและสคีมา ที่อาจจะหลีกเลี่ยงได้โดยมีแหล่งเดียวของความเป็นจริงเช่นโดยการใช้หรือts-mongoose typegooseสถานการณ์จะซ้ำซ้อนมากขึ้นเมื่อกำหนดสคีมา GraphQL
Dan Dascalescu

วิธีใดในการกำหนด refs ด้วยแนวทางนี้?
Dan Dascalescu

2

ผมแฟน ๆ ของ Plumier แต่ก็มีผู้ช่วยพังพอน , แต่ก็สามารถนำมาใช้แบบสแตนด์อโลนโดยไม่ต้อง Plumier ตัวเอง ซึ่งแตกต่างจาก Typegoose ซึ่งใช้เส้นทางที่แตกต่างกันโดยใช้ไลบรารีภาพสะท้อนเฉพาะของ Plumier ซึ่งทำให้สามารถใช้ของเจ๋ง ๆ

คุณสมบัติ

  1. Pure POJO (โดเมนไม่จำเป็นต้องสืบทอดจากคลาสใด ๆ หรือใช้ชนิดข้อมูลพิเศษใด ๆ ) แบบจำลองที่สร้างขึ้นโดยอัตโนมัติอนุมานว่า T & Documentไปได้ในการเข้าถึงคุณสมบัติที่เกี่ยวข้องกับเอกสาร
  2. คุณสมบัติพารามิเตอร์ TypeScript ที่รองรับจะดีเมื่อคุณมี strict:trueคอนฟิกูเรชัน tsconfig และด้วยคุณสมบัติพารามิเตอร์ไม่จำเป็นต้องมีมัณฑนากรในคุณสมบัติทั้งหมด
  3. คุณสมบัติของฟิลด์ที่รองรับเช่น Typegoose
  4. การกำหนดค่าจะเหมือนกับพังพอนดังนั้นคุณจะคุ้นเคยกับมันได้ง่าย
  5. การสืบทอดที่รองรับซึ่งทำให้การเขียนโปรแกรมเป็นธรรมชาติมากขึ้น
  6. การวิเคราะห์โมเดลแสดงชื่อโมเดลและชื่อคอลเลคชันที่เหมาะสมใช้การกำหนดค่าเป็นต้น

การใช้งาน

import model, {collection} from "@plumier/mongoose"


@collection({ timestamps: true, toJson: { virtuals: true } })
class Domain {
    constructor(
        public createdAt?: Date,
        public updatedAt?: Date,
        @collection.property({ default: false })
        public deleted?: boolean
    ) { }
}

@collection()
class User extends Domain {
    constructor(
        @collection.property({ unique: true })
        public email: string,
        public password: string,
        public firstName: string,
        public lastName: string,
        public dateOfBirth: string,
        public gender: string
    ) { super() }
}

// create mongoose model (can be called multiple time)
const UserModel = model(User)
const user = await UserModel.findById()

1

สำหรับใครก็ตามที่กำลังมองหาทางออกสำหรับโครงการพังพอนที่มีอยู่:

เมื่อเร็ว ๆ นี้เราได้สร้างพังพอน -sgenเพื่อแก้ไขปัญหานี้ (ยินดีรับข้อเสนอแนะ!) โซลูชันที่มีอยู่เช่น typegoose จำเป็นต้องเขียนแผนผังทั้งหมดของเราใหม่และนำเสนอความเข้ากันไม่ได้ต่างๆ mongoose-tsgenเป็นเครื่องมือ CLI อย่างง่ายซึ่งสร้างไฟล์ index.d.ts ที่มีอินเตอร์เฟส typescript สำหรับโครงร่างพังพอนทั้งหมดของคุณ ต้องใช้การกำหนดค่าเพียงเล็กน้อยหรือไม่มีเลยและรวมเข้ากับโครงการ typescript ได้อย่างราบรื่น


1

หากคุณต้องการให้แน่ใจว่าสคีมาของคุณตรงตามประเภทโมเดลและในทางกลับกันโซลูชันนี้ให้การพิมพ์ที่ดีกว่าที่ @bingles แนะนำ:

ไฟล์ประเภททั่วไป: ToSchema.ts(อย่าตกใจ! เพียงแค่คัดลอกและวาง)

import { Document, Schema, SchemaType, SchemaTypeOpts } from 'mongoose';

type NonOptionalKeys<T> = { [k in keyof T]-?: undefined extends T[k] ? never : k }[keyof T];
type OptionalKeys<T> = Exclude<keyof T, NonOptionalKeys<T>>;
type NoDocument<T> = Exclude<T, keyof Document>;
type ForceNotRequired = Omit<SchemaTypeOpts<any>, 'required'> & { required?: false };
type ForceRequired = Omit<SchemaTypeOpts<any>, 'required'> & { required: SchemaTypeOpts<any>['required'] };

export type ToSchema<T> = Record<NoDocument<NonOptionalKeys<T>>, ForceRequired | Schema | SchemaType> &
   Record<NoDocument<OptionalKeys<T>>, ForceNotRequired | Schema | SchemaType>;

และโมเดลตัวอย่าง:

import { Document, model, Schema } from 'mongoose';
import { ToSchema } from './ToSchema';

export interface IUser extends Document {
   name?: string;
   surname?: string;
   email: string;
   birthDate?: Date;
   lastLogin?: Date;
}

const userSchemaDefinition: ToSchema<IUser> = {
   surname: String,
   lastLogin: Date,
   role: String, // Error, 'role' does not exist
   name: { type: String, required: true, unique: true }, // Error, name is optional! remove 'required'
   email: String, // Error, property 'required' is missing
   // email: {type: String, required: true}, // correct 👍
   // Error, 'birthDate' is not defined
};

const userSchema = new Schema(userSchemaDefinition);

export const User = model<IUser>('User', userSchema);



0

นี่คือตัวอย่างที่อ้างอิงจาก README สำหรับ@types/mongooseแพ็คเกจ

นอกจากองค์ประกอบที่รวมไว้แล้วข้างต้นยังแสดงวิธีการรวมวิธีการปกติและแบบคงที่:

import { Document, model, Model, Schema } from "mongoose";

interface IUserDocument extends Document {
  name: string;
  method1: () => string;
}
interface IUserModel extends Model<IUserDocument> {
  static1: () => string;
}

var UserSchema = new Schema<IUserDocument & IUserModel>({
  name: String
});

UserSchema.methods.method1 = function() {
  return this.name;
};
UserSchema.statics.static1 = function() {
  return "";
};

var UserModel: IUserModel = model<IUserDocument, IUserModel>(
  "User",
  UserSchema
);
UserModel.static1(); // static methods are available

var user = new UserModel({ name: "Success" });
user.method1();

โดยทั่วไป README นี้ดูเหมือนจะเป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับการเข้าใกล้ประเภทที่มีพังพอน


วิธีการนี้ซ้ำความหมายของทุกสาขาจากIUserDocumentเข้ามาUserSchemaซึ่งจะสร้างความเสี่ยงการบำรุงรักษาเป็นแบบจำลองจะกลายเป็นความซับซ้อนมากขึ้น แพคเกจชอบts-mongooseและtypegooseพยายามที่จะแก้ปัญหานั้นแม้ว่าจะยอมรับว่ามีข้อบกพร่องทางวากยสัมพันธ์อยู่บ้างก็ตาม
Dan Dascalescu

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.