szokodiakos / typegoose Goto Github PK
View Code? Open in Web Editor NEWTypegoose - Define Mongoose models using TypeScript classes.
License: MIT License
Typegoose - Define Mongoose models using TypeScript classes.
License: MIT License
Mongoose's schema has some configurable options and you can use them like:
new Schema({...}, options)
Is it possible to set them in Typegoose?
Dear Szokodiakos
Thank you for Typegoose that helps a lot in simplifying code and improve maintainability. I have an issue and could not understand why and how it happens when using 'mongoose-paginate' as the Typegoose plugin, I have followed the guides for similar issue in this git but it still does not work, could you help look at and kindly advise why plugin does not return result?
Extracted code is as below (which worked well if I use plugin with native mongoose but not via Typegoose)
import {
prop,
Typegoose,
InstanceType,
staticMethod,
plugin,
} from 'typegoose';
// tslint:disable-next-line:no-var-requires
import * as paginate from "mongoose-paginate";
export interface PageinateResult {
docs: [InstanceType];
total?: number;
limit?: number;
}
@plugin(paginate)
export class ClientType extends Typegoose {
@prop({ required: true, minlength: 5, index: true })
name: string;
@prop()
status?: string;
static paginate: (query, options) => Promise<PageinateResult<ClientType>>;
// I thought the issue happens here but try several scenarios still not work
}
export const model = new ClientType().getModelForClass(ClientType);
Then
// As I use multi DB thus below
var client = new ClientType().getModelForClass(ClientType, {schemaOptions: {collection: 'Client'}, existingConnection: mongooseConnection});
Where I expect it returns the documents, it only return the unfulfilled Promise
client.paginate(query, options)
.then(result => {
console.log(result)
});
Thank you for your advices.
Hi.
I'm using yet typegoose 3.5.2 because 3.6.0 don't works for me (see #68).
I defined a model with the "_id" field to simplify the configuration of data on db. This is not frequently but it works and it is admitted with mongoose.
When I load in memory a doc defined with an array of items wich are defined with an "_id" field, the array is empty.
Below the source file.
import * as tg from 'typegoose';
export class perm extends tg.Typegoose {
@tg.prop() routerFunction : string;
@tg.prop() permit: boolean;
}
export const permModel = new perm().getModelForClass(perm);
export class group extends tg.Typegoose {
@tg.prop( { required: true, index: true, unique: true } ) _id: string;
@tg.prop( { required: true, index: true, unique: true } ) name : string;
@tg.arrayProp( { itemsRef: perm } ) perms ?: tg.Ref<perm>[];
}
export const groupModel = new group().getModelForClass(group);
export class admin extends tg.Typegoose {
@tg.prop() name : string;
@tg.arrayProp( { itemsRef: group } ) groups ?: tg.Ref<group>[];
@tg.arrayProp( { itemsRef: perm } ) perms ?: tg.Ref<perm>[];
}
export const adminModel = new admin().getModelForClass(admin);
adminModel.findById('an id').exec((err, data) => {
console.log(data); // prints correctly the perms array data but an empty groups array
}
Hi.
Please, can you help me to solve a problem with reciprocal reference fields in the models?
Yes, it seems strange but usefull in something situations.
If you have two classes with reciprocal reference fields in the models, you can receive an Error (In property user: Object is not a primitive type nor a Typegoose schema (Not extending it).) during che compilation phase.
Maybe because one of the classes is not yet defined. This happens also if the two classes are in the same file.
I searched for a foreward instruction without success.
Below a short example:
import { prop, staticMethod, instanceMethod, Typegoose, ModelType, InstanceType, Ref } from 'typegoose';
export class Admin extends Typegoose {
@prop() firstName: string;
@prop({ ref: User }) user?: Ref<User>;
}
export const AdminModel = new Admin().getModelForClass(Admin);
export class UserRole {
@prop({ ref: Admin }) admin?: Ref<Admin>;
}
export class User extends Typegoose {
@prop({ required: true }) email: string;
@prop({ required: true }) username: string;
@prop() roles?: UserRole;
}
export const UserModel = new User().getModelForClass(User);
Thank you in advance.
Models containing fields of a custom class type seem to always be created when retrieving a document from the collection, even if said field is optional.
For example, the model:
class Thing extends Typegoose {
@prop() text: string;
}
class Container extends Typegoose {
@prop() numeric: number;
@prop() custom?: Thing;
}
The collection:
[ { numeric: 1 } ] // _id omitted for brevity
If you query and log the result to the console, it logs the expected value
Collection.findOne({ numeric: 1 }).then(r => console.log(r));
logs
{ numeric: 1 } // _id omitted for brevity
But you can somehow still access the non-existent 'custom' field and it will return an empty object
Collection.findOne({ numeric: 1 }).then(r => console.log(r['bonus']));
logs
{ }
whereas it should be undefined
since it isn't defined in the document.
I'm not exactly sure that this is Typegoose's fault, but I don't think this should happen using just Mongoose, but I haven't tried. 😕
I have two DB with a Mongoose instance for each one, which I use as an existingMongoose
property when I create a new getModelForClass
instance.
In a model associated to the first Mongoose instance I have a ref to a model in the second Mongoose instance.
And of course, when I try to populate the ref of the first model (Which refers to the second Mongoose instance) I get a MissingSchemaError: Schema hasn't been registered for model
because it is not registered in the first Mongoose instance.
This is supported by Mongoose (http://mongoosejs.com/docs/populate.html#cross-db-populate) but Typegoose expects a fully Mongoose instance, not a connection created with createConnection
to associate a model to it.
Is there any workaround for this??
(I'm open to implement this if you give me some guidance :) )
I have not found any reference about how to define compound indexes using Typegoose.
Is there any way to do it?
Thanks.
Hi.
It's very usefull the 'expires' option for the schema field definition when data type is Data.
Below a mongoose example:
new Schema({
createdAt: { type: Date, expires: 60*60*24 }
});
Please, can you consider to implement it?
Thank you!
_\node_modules\mongoose\lib\index.js:477
if (schema.$globalPluginsApplied) {
TypeError: Cannot read property '$globalPluginsApplied' of undefined
at Mongoose._applyPlugins (_\node_modules\mongoose\lib\index.js:477:14)
at Mongoose._applyPlugins (_\node_modules\mongoose\lib\index.js:487:10)
at Mongoose.model (_\node_modules\mongoose\lib\index.js:396:10)
at TestModel.setModelForClass (_\node_modules\typegoose\lib\typegoose.js:44:31)
at TestModel.getModelForClass (_\node_modules\typegoose\lib\typegoose.js:20:18)
Setup looks like the following:
export const TestModel = new Test().getModelForClass(Test, {existingConnection: mongoose});
export class Test extends Typegoose {
@prop({index:true})
userId:string;
@arrayProp({ items: Item})
items?: Item[];
export class Item extends Typegoose {
@prop({index:true})
id:string;
@prop()
name: string;
}
using mongoose 4.13.6
I'm getting this erros while running the test in master, it seems to be related to the last changes of plugins.
> [email protected] lint /home/dgomez/Proyectos/OpenSource/typegoose
> tslint --type-check --project tsconfig.json
Error at src/typegoose.ts:53:29: Property 'mongoosePlugin' does not exist on type 'string'.
Error at src/typegoose.ts:53:52: Property 'options' does not exist on type 'string'.
Error at src/typegoose.ts:59:19: Property 'get' does not exist on type 'string'.
Error at src/typegoose.ts:60:38: Property 'get' does not exist on type 'string'.
Error at src/typegoose.ts:62:19: Property 'set' does not exist on type 'string'.
Error at src/typegoose.ts:63:38: Property 'set' does not exist on type 'string'.
I want to save a mongoose document with a typegoose sub-document but data isn't saving correctly.
Car Model does not extend Typegoose
import * as mongoose from 'mongoose' const Model = mongoose.Schema const CarModel = new Model ({ color: String, driver: { type: Schema.Types.ObjectId, ref: 'UserModel' }, })
UserModel extends Typegoose
`export class User extends Typegoose {
@prop()
public name: string;
}
export const UserModel = new User().getModelForClass(User)`
Different file to create Data to save
const autoMobile = {};
autoMobile.color = 'black';
autoMobile.driver = new UserModel({name: 'Bob'});
Car.create(autoMobile, (createdCar: any) => { return createdCar; })
Everything is saved correctly except the name attribute on the userModel. Mogoose even creates the ID correctly. Any help is much appreciated
Would it be possible to remove the id
field from the Typegoose class?
My documents have their own id
field which are numbers instead of strings, so TypeScript gives me an error telling me that I haven't extended the Typegoose class properly. However, removing the id
field from the Typegoose typings allows it to compile and work just fine.
If having the id
field is necessary in some way, maybe consider renaming it to _id
since id
does not necessarily seem to be reserved in MongoDB.
I want to do the following (regular Mongoose):
let personSchema = new mongoose.Schema({
id: String,
address: {
street: String,
streetnumber: Number,
}
});
With Typegoose:
class Person extends Typegoose {
@prop()
id: string;
@prop()
address: {
street: string;
streetnumber: number;
}
});
But it says: Object is not a primitive type nor a Typegoose schema (Not extending it).
If i do like described in the readme(creating a seperate class for address) Typegoose would create a new schema and a seperate document for address and that is not what i want to do.
Does props have the index option
I can't make @instancemethod work at all. Even with this simple example:
// on the User model class:
@instanceMethod
public changeName(this: InstanceType<User>) {
this.name = "blabla";
}
In some other file where I create an User:
const user: User = await UserService.getOneBy...(..); //this succesfully creates an user based on db
user.doSomething();
I get this error:
error TS2684: The 'this' context of type 'User' is not assignable to method's 'this' of type 'InstanceType<User>'.
Type 'User' is not assignable to type 'Document'.
Property 'increment' is missing in type 'User'.
Any clue?
Thanks in advance!
José
I probably made a mistake implementing Typegoose somewhere (btw, awesome project!) but on the first User.findOne()
my request is freezing.
This is my (simplified) model:
export class UserClass extends Typegoose {
@prop()
_id: string
@prop({
required: true
})
name: string
@prop({
required: true
})
email: string
@prop({
required: true
})
password: string
}
Exposed like this:
export const User = new UserClass().getModelForClass(UserClass)
And called like this:
import { UserClass, User } from 'server/models/user/model'
const user = await User.findOne({
email
})
But it gets stuck on the User.findOne
line and never returns from it.
Last thing the console prints before that is DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated
even though I'm using (mongoose as any).Promise = Promise
.
Before Typegoose I didn't get the deprecation warning and the Promise line did work.
Typegoose 3.6.0
Node v8.5.0
Any ideas?
If you have a class that contains itself, you get a maxed call stack error.
For example,
class Thing {
@arrayProp({ items: Thing })
other: Thing[];
}
Hi guys,
Is it possible to use the same class on the front end of the app? (For example on an Angular app)?
Cheers~
type Method = 'init' | 'validate' | 'save' | 'remove';
please add all methods, like 'findOne', 'find' ... etc.
i can't create a class with @pre findOne
Hi.
Great job but I have encountered maybe a trouble:
If I use the 'find' method of my little example in that I defined only two fields (username and email), if there are more fields in the database (firstname, lastname, username, email, password, ...), Typegoose load all the field. If I use the mongoose schema, mongoose load only the two field. It seems like when you define an empty schema.
Can you explain me that?
Below I attached my source files: server, the model and a route page.
user.model.ts
IndexRoute.ts
server.ts
Thank you! Typegoose is really THE typescript solution for mongoose.
EDIT (06/oct/2017):
I found the solution using the 'projection' parameter of the 'find' method.
I don't know if there is a typegoose method or a better idea to compose the projection string:
let proj = Object.keys(UserModel.schema.obj).join(' ');
public index(req: Request, res: Response, next: NextFunction) {
let proj = Object.keys(UserModel.schema.obj).join(' ');
UserModel.find({}, proj, (err, data) => {
if(err) {
res.status(200).json({msg: 'err', "err": err});
return next(err);
}
res.status(200).json({msg: 'ok', "data": data});
// prints:
// {"msg":"ok","data": [{"_id":"57669d50a87cfa704393bf54","username":"myusername","email":"[email protected]"}]}
});
}
Is there any way to use the very useful Plugins from mongoose ? Or anything allowing me to re-use a bunch of properties in several models ?
Re-using the a sub schema could be a solution but it does not allow custom pre-validation on on the added properties. I've also tried using typescript mixins, but this method needs to redeclare the variables in the implementing class.
Any ideas about this ?
Thanks in advance.
Hi.
I used an old version of typegoose and all works correctly.
To day I tested the 3.6.0 version of Typegoose and I encountered some troubles.
I tested my project with the 3.5.2 version of Typegoose and it works correctly again.
With the debugger I checked that the execution is looped at the count instance method of 'pgLoginAttemptModel' in the 'getIpUserCount' function.
The source file is:
import * as async from 'async';
export class pgLoginAttempt extends Typegoose {
@prop({ default: '', index: true }) ip: string;
@prop({ default: '', index: true }) user: string;
@prop({ default: Date.now()}) time: Date;
}
export const pgLoginAttemptModel = new pgLoginAttempt().getModelForClass(pgLoginAttempt, { schemaOptions: { collection: 'pg-login-attempts'}});
protected abuseFilter(successEvent: string) {
let getIpCount = (done) => {
let conditions = { ip: req.app.ip };
pgLoginAttemptModel.count(conditions, (err, count) => {
if (err) return done(err);
done(null, count);
});
};
let getIpUserCount = (done) => {
let conditions = { ip: req.app.ip, user: req.body.username };
pgLoginAttemptModel.count(conditions, (err, count) => {
if (err) return done(err);
done(null, count);
});
};
let asyncFinally = (err, results) => {
if (err) return this.emit(this.err, err);
if (results.ip >= 5 || results.ipUser >= 5) {
return this.emit(this.fail);
}
else {
this.emit(successEvent);
}
};
async.parallel({ ip: getIpCount, ipUser: getIpUserCount }, asyncFinally);
};
I would love to see the reflection capabilities with class instances, just like obj.constructor
works like.
I use class-transformer
for document serialization:
import { Typegoose, prop as Property } from "typegoose";
import { Exclude, Expose } from "class-transformer";
@Exclude()
export class User extends Typegoose {
@Expose()
id: string;
@Expose()
@Property({ unique: true })
email: string;
@Property()
password: string;
}
export const UserModel = new User().getModelForClass(User);
It would be amazing to be able to write generic serialize
method which could take the original ClassType
from the mongoose document and invoke plaintToClass(ClassType, object)
without explicit specifying the constructor class function.
Examples:
// instead writing in http framework controllers methods
const dbUser = await UserModel.findOne({ email: "test" });
const clsUser = plainToClass(User, dbUser!);
return classToPlain(clsUser);
// I would like to return plain document
return await UserModel.findOne({ email: "test" });
// and the `serialize` method would be invoked by http framework before sending response to client
function serialize(document) {
const ClassType = getClassTypeForTypegooseDocument(document);
return plainToClass(ClassType, document);
}
I know that your main goal is to define the schema by class but since you don't return the class itself as a document (like TypeORM does) it would be necessary to provide posibility to get the class of the document of schema created by the class 😉
I think that the best way would be to store this.constructor
function from getModelForClass
inside typegoose's constructors
dictionary and then get the constructor by model name with the model name from docObj.constructor.modelName
😃
Something like:
class GuildMember extends Typegoose {
@prop({ref: User})
public user: Ref<User>;
public get id() {
return this.user.identifier; // <------ identifier doesn't exist on `Ref`
}
}
Typegoose automatically pluralizing my collection names. for example my collection is device_warehouse, on the db it became device_warehouses with "s". I hope I can get feedback soon.
I'm not quite sure why there is an agrupation of the "allowed" SchemaType Options (required, enum, default, min, max, etc) in the code (BasePropOptions, ValidateNumberOptions, etc). I guess you want TS to ensure what is being sent in the @prop() and @arrayProp() annotations... right?
The annoying part of this is that we should add the missing SchemaType Options manually 😢
I've already tested adding unique and index in the BasePropOptions:
export interface BasePropOptions {
unique?: boolean; // Unique is always boolean!
index?: boolean; // Same here.
...
...and they work just fine. Would you like a PR for this? This is another simple addition ;)
Hi,
I'm for some reason getting this error "TypeError: Class constructor Typegoose cannot be invoked without 'new'"
I have a class like this:
export class Item extends Typegoose {
@prop()
name: string;
@prop()
description: string;
@prop({ref: Asset})
question: Asset;
@prop({enum: ItemTypes})
itemType: ItemTypes;
@prop({enum: ItemModes})
itemMode: ItemModes;
}
I also have service which uses the class like this:
export class ItemsService {
private itemModel;
constructor(
) {
this.itemModel = new Item().getModelForClass(Item);
}
}
As TS compiles:
TypeError: Class constructor Typegoose cannot be invoked without 'new'
at new Item (/Users/anvlkv/Projects/intervey/intervey-api/src/models/item.ts:40:42)
at new ItemsService (/Users/anvlkv/Projects/intervey/intervey-api/src/server/services/itemsService.ts:11:20)
at new SequenceService (/Users/anvlkv/Projects/intervey/intervey-api/src/server/services/sequenceService.ts:13:23)
at Object.<anonymous> (/Users/anvlkv/Projects/intervey/intervey-api/src/server/routes/InterviewerRoutes.ts:9:42)
at Module._compile (module.js:570:32)
at Module.m._compile (/Users/anvlkv/Projects/intervey/intervey-api/node_modules/ts-node/src/index.ts:392:23)
at Module._extensions..js (module.js:579:10)
at Object.require.extensions.(anonymous function) [as .ts] (/Users/anvlkv/Projects/intervey/intervey-api/node_modules/ts-node/src/index.ts:395:12)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/Users/anvlkv/Projects/intervey/intervey-api/src/server/main.ts:4:1)
at Module._compile (module.js:570:32)
at Module.m._compile (/Users/anvlkv/Projects/intervey/intervey-api/node_modules/ts-node/src/index.ts:392:23)
[nodemon] app crashed - waiting for file changes before starting...
The strangest part is that my src/models/item.ts is only 33 lines and problem supposed to be at line 40.
This makes hashing passwords almost impossible for me.
code to reproduce:
@pre<User>('save', function(next) {
if (this.isModified("password") || this.isNew) {
// errors
}
})
Is there any way to use typegoose with fields of type 'any' or 'object'?
Hi, I'm trying typegoose since yesterday, and I have a question related to your implementation. (Thanks a lot for your work, this package rocks!):
Why can't we assign a model as a type?
import { prop, Typegoose} from 'typegoose'
class User extends Typegoose {
...
@prop({ required: true})
public firstName: string;
...
}
export default new User().getModelForClass(User);
import User from './User'
let user:User = new User(); // -> Does not work because User is not a type
If you put { required: true } in the prop annotation over a nested element you get this error:
TypeError: Undefined type undefined
at job.required
Did you try nesting Schemas? You can only nest using refs or arrays.
You can try it with the same code of your md file example:
class Job extends Typegoose {
@prop()
title: string;
@prop()
position: string;
}
class Contact extends Typegoose {
@prop({ required: true }) // Added the required constraint
job: Job;
}
The work around is... not using "required: true" over nested elements (yay!).
I'm using:
Hapi 16.4.3,
typegoose 3.0.0,
typescript 2.4.1,
ts-node 3.1.0,
Once again, let me know if you can reproduce this.
Thanks in advance!
Using the following code:
export default abstract class AbstractModel extends Typegoose {
@staticMethod
public static findByIdentifier(this: ModelType<AbstractModel>, identifier: Long) {
return new Promise((resolve, reject) => {
console.log(this);
this.findOne({identifier}).then(resolve).catch(reject);
});
}
@prop({required: true, index: true, unique: true})
public identifier: string;
}
this
is always an instance of the model, instead of the model type, so i can't call findOne
.
Feel like im missing something...
When running tsc
, there are tons of duplicatie identifier
errors if you have both typegoose
and @types/mongoose
installed.
Removing the latter solves the issue.
I got the following error when trying to nest models...:
Error: There is no metadata for the "job" property. Check if emitDecoratorMetadata is enable in tsconfig.json
at [...]/node_modules/typegoose/src/prop.ts:148:11
... if the nested model is defined after the parent one (this is the same example of your md file, without the Car ref):
import { prop, Typegoose } from 'typegoose';
class User extends Typegoose {
@prop()
name?: string;
@prop({ required: true })
age: number;
@prop()
job?: Job;
}
class Job extends Typegoose {
@prop()
title?: string;
@prop()
position?: string;
}
export const UserModel = new User().getModelForClass(User);
The work around is to define Job before User.
I'm using:
Hapi 16.4.3,
typegoose 3.0.0,
typescript 2.4.1,
ts-node 3.1.0,
And yes, I have "emitDecoratorMetadata": true in tsconfig 😉
Let me know if you can reproduce this!
Thanks!
I have my class like this:
export class User extends Typegoose {
}
How can I add mongoose.Document
or InstanceType
to it? Because now I have to do this in all my functions:
export async function addUser(args: IAddUserArgs): Promise<User & mongoose.Document> {
}
Which is a bit annoying because I have to import mongoose in every file that imports User.
I'm not sure how to do this with my limited TS knowledge :)
If a schema has no instance methods defined by the user, mongoose will still try to access its structure when timestamps are enabled for it.
The following error will occur:
TypeError: Cannot set property 'initializeTimestamps' of undefined
The cause is that schema.methods is undefined and mongoose tries to add a new method by:
this.methods.initializeTimestamps = function { ... }
A solution to this is simple: typegoose.ts:37:
sch.methods = instanceMethods || {};
First of all, The idea is awesome!
I just wanted to know about how to implement 'pre' and 'pos' save methods in typegoose way.
Thanks!
I'm using typegoose 3.6.0 with mongoose 4.13.0.
Setting mongoose.Promise doesn't work when using Typegoose, even if setting it everywhere I import mongoose. As a result (I'm assuming) the mongoose promises are never executed. Removing Typegoose solves the problem.
Eveywhere I import mongoose:
const mongoose = require("mongoose")
(<any>mongoose).Promise = global.Promise;
Defining the model:
export enum Role {
USER = "user",
CONTRIBUTOR = "contributor",
ADMIN = "admin"
}
export class UserProto extends Typegoose {
_id: mongoose.Types.ObjectId;
createdAt: Date;
updatedAt: Date;
@prop({ enum: Role, default: Role.USER })
role: Role;
}
export const User = new UserProto().getModelForClass(UserProto, { schemaOptions: { timestamps: true }});
"in save" is never logged
let user = new User({role: Role.USER});
user.save().then((doc) => {
console.log("in save");
return doc.toObject();
}).catch((err) => {
console.log("error");
});
Hi.
I'm using typegoose increasingly in a production project; it works and keep clean the source code. Thank you!
Maybe, in the README.md file you can specify the following tips about 'plugin':
If the plugin is developed with Typescript language and it is not a 3rd part software, check the first line of the transpilled file.
From Typescript 2.2 the first transpilled js line after the 'use strict' line, is 'Object.defineProperty(exports, "__esModule", { value: true });' and a mongoose error is generated because a function is needed at start of plugin.
To avoid this error you can start the plugin in the Typescript source file with the line:
module.exports = exports = function findOrCreatePlugin (schema, options?) {
...
}
staticMethod decorator and an empy body {} are mandatory for a correct and complete method signature also when you add manually the static methods for typing information about a schema.statics function in a plugin.
@staticMethod public static findOrCreate(condition: InstanceType<User>): Promise<{ doc: InstanceType<User>, created: boolean }> {};
Whitout these two warnings in the README.md it's possible to lose a lot of work time.
Why mongoose
is a real dependency of typegoose? It should be a peerDependency and users should install it by themselves, as they still need to explicitly use it by themselves:
import * as mongoose from 'mongoose';
mongoose.connect('mongodb://localhost:27017/test');
So when they use different version than the typegoose
one, there will be problems with no errors marked by npm - two copies of mongoose in one project.
Also, you distribute on npm the compiled version and "main"
points to "lib/typegoose.js"
which is correct. So why you have typescript
listed in dependecies? Lib consumers doesn't need this, they can use the lib even with flow+babel, as long as they produce api-compatible js transpiled code.
import 'reflect-metadata';
is also not needed in typegoose source - it's only a runtime shim for Reflect.metadata
to make TS decorator class type reflection works. Again, users should import it in their entry file as some of them might want to use core-js
polyfill instead.
Hi,
I am trying to use Typegoose with feathers-mongoose and I guess I am making some beginner´s mistake, because I can´t get it to work.
My model class looks like this:
export class PostalCode extends Typegoose{
@prop({ required: true })
code: String
@prop({ required: true })
city: String
}
I thought, I could simply replace the model creation (which is commented out and works fine) with the getModelForClass statement, but this doesn´t work:
const service = require('feathers-mongoose');
function services() {
/* var postalCodeSchema = mongoose.Schema({
code: String,
city: String
});
var PostalCodeModel = mongoose.model('PostalCode', postalCodeSchema); */
var PostalCodeModel = new PostalCode().getModelForClass(PostalCode);
this.use('/postalcode', service({
Model: PostalCodeModel,
paginate: {
default: 2,
max: 4
}
}));
}
I would be great if you could give me a hint, what I did wrong.
Thanks Alex
Hi. I'm trying to follow your example and having difficulties.
my project structure is:
app.ts
server.ts
models
-->user.model.ts
routes
-->users.ts
in app.ts I'm defining the connection to the database:
constructor() {
this.mongoose = new mongoose.Mongoose();
this.express = express();
this.express.use("/users", usersRouter);
this.mongoose.connect("mongodb:\/\/localhost:27017/example", (err) => {
if (err) {
console.log('[-] Error connecting to database mongodb:\/\/localhost:27017/example" - ${err.message}');
throw err;
} else {
console.log('[*] Connected to database mongodb:\/\/localhost:27017/example');
}
});
}
server.ts is only there to start the server itself:
let app = new App();
app.express.listen(3000, () => {
console.log('[*] server started on port 3000');
});
I've created a user model with Typegoose and added an API call via express to add a user to the system:
routes/users.ts (where i call 'addUser' from the model):
private static readonly UserModel = new User().getModelForClass(User);
usersRouter.post("/register", (req, res, next) => {
let newUser = new Models.UserModel({
email: req.body.email,
name: req.body.name,
password: req.body.password,
username: req.body.username,
});
UserModel.addUser(newUser, (err, user) => {
if (err) {
res.json({
msg: "Failed regisgter user",
success: false,
});
} else {
res.json({
msg: "registered user",
success: true,
});
}
});
}
models/user.model.ts
export class User extends Typegoose {
@staticMethod
public static async addUser(newUser: InstanceType<User>, callback: (err: any, product: InstanceType<User>) => void)) {
await newUser.save(callback);
}
@prop({required: true})
public email: string;
@prop()
public name?: string;
@prop({required: true})
public password: string;
@prop({required: true})
public username: string;
}
everything's going fine until the line newUser.save();
the callback never get called... I also don't see any traffic in mongo.
The project work on JavaScript, now I'm trying to move to TS. Is there something I missed during the transmission or is it an issue?
Using @plugin without have in an @staticmethod leaves the schema.statics uninitialized.
Why does one have to use @staticMethod
and @instanceMethod
decorators to declare methods? Why aren't all class methods just handled automatically?
Hi,
is it possible to use GeoJSON with Typegoose?
I'm not able to create an index so I can search it with $nearSphere.
What I've tried is to create the following model to store the data:
export class LocationData extends Typegoose {
@prop()
public type: string;
@arrayProp({ items: Number })
public coordinates: [number];
}
In my user model I have added the following attribute:
export class User extends Typegoose {
@prop()
public currentLocation: LocationData;
}
Since there must be an index on currentLocation to be able to perform the $nearSphere query I tried @prop({index: true})
.
But I got the following error message:
TypeError: Undefined type `undefined` at `currentLocation.index`
Did you try nesting Schemas? You can only nest using refs or arrays.
Some tutorials said you must define your own type to store the location data.
But how do I do it with Typegoose?
The mongoose way is:
var locationSchema = new Schema({
loc: {
type: {
type: "String",
required: true,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
},
coordinates: [Number]
}
});
locationSchema.index({ 'loc': '2dsphere' });
var Location = mongoose.model( 'Location', locationSchema );
What do I need to do to solve this issue?
just like in demo user.ts
@instancemethod
addJob(this: InstanceType) {
this.previousJobs.push({ title: 'Janitor'});
this.save();
}
i got error.
Right now, you support string array as an enum:
// Enum-like type and definition example.
type Gender = 'male' | 'female';
const Genders = {
MALE: 'male' as Gender,
FEMALE: 'female' as Gender,
};
@prop({ enum: Object.values(Genders) })
gender?: Gender;
However we have string enum support in TS now. It would be nice if the decorator function accept also the object
type as the enum
value and get the string values using Object.values(object)
inside:
// true enum type
enum Gender {
MALE = 'male',
FEMALE = 'female',
};
@prop({ enum: Gender })
gender?: Gender;
So the signature of the BasePropOptions
would be enum?: string[]|object;
and you can in runtime check if Array.isArray(enum)
to behave like now or convert enum object to values.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.