mongot
Version:
MongoT is a modern ODM library for MongoDb.
335 lines (235 loc) • 7.2 kB
Markdown
# MongoT
MongoT is a modern ODM library for MongoDb.
## Install
Just type `npm i -S mongot` to install this package.
## Usage
### Configure
You may need TypeScript 2+ and should enable `experimentalDecorators`,
`emitDecoratorMetadata` in your `tsconfig.json`.
### Collections
A collection is a class which support CRUD operations for own
documents.
#### Create a collection
Let's create a simple collection and name it as `UserCollection`:
```ts
# UserCollection.ts
import {Collection, collection} from 'mongot';
import {UserDocument} from './UserDocument';
@index('login', {unique: true})
@collection('users', UserDocument)
class UserCollection extends Collection<UserDocument> {
findByEmail(email: string) {
return this.findOne({email});
}
}
```
Any collections should refer to their own document schemas so
we link the class `UserCollection` to a `users` collection in
database and a `UserDocument` schema by a `@collection` decorator.
### Document Schema
A document class describes a schema (document properties, getters/setters,
hooks for insertions/updates and helper functions).
Schema supports these types: `ObjectID`, `string`, `boolean`, `number`,
`date`, `Object`, `SchemaFragment` (also known as sub-document)
and `array`. A `buffer` type doesn't tested at this time.
#### Create schema
To describe schema you need write a class with
some properties decorated with `@prop` decorator
and define property type. Just look at UserDocument
schema example:
```ts
# UserDocument.ts
import {SchemaDocument, SchemaFragment, Events} from 'mongot';
import {hook, prop, document} from 'mongot';
import * as crypto from 'crypto';
@fragment
class UserContactsFragment extends SchemaFragment {
type: 'phone' | 'email' | 'im';
title: string;
value: string;
}
@document
class UserDocument extends SchemaDocument {
@prop
public email: string;
@prop
public password: string;
@prop
public firstName: string;
@prop
public lastName: string;
@prop
registered: Date = new Date();
@prop
updated: Date;
@prop(UserContactsFragment)
children: SchemaFragmentArray<UserContactsFragment>;
@hook(Events.beforeUpdate)
refreshUpdated() {
this.updated = new Date();
}
get displayName() {
return [this.firstName, this.lastName]
.filter(x => !!x)
.join(' ') || 'Unknown';
}
checkPassword(password: string) {
return this.password === crypto.createHash('sha1')
.update(password)
.digest('hex');
}
}
```
### Usage
#### Repository
Repository is an util for creating connections to server
and get connected collections.
Example:
```ts
# index.ts
import {Repository} from 'mongot';
const options = {};
const repository = new Repository('mongodb://localhost/test', options);
```
The `Repository` class constructor has same arguments that
MongoClient.
#### Documents
You can creating documents in two ways.
Using `Collection.factory` method:
```ts
# document-factory.ts
import {Repository} from 'mongot';
import {UserCollection} from './UserCollection';
const repository = new Repository('mongodb://localhost/test', {});
async function main(): void {
const users: UserCollection = repository.get(UserCollection);
const user = users.factory({
email: 'username@example.com',
firstName: 'Bob'
});
console.log(user);
// saving document
await users.save(user);
}
main();
```
Using `DocumentSchema` constructor:
```ts
# document-constructor.ts
import {Repository} from 'mongot';
import {UserCollection} from './UserCollection';
const repository = new Repository('mongodb://localhost/test', {});
async function main(): void {
const users: UserCollection = repository.get(UserCollection);
const user = new UsersDocument({
email: 'username@example.com',
firstName: 'Bob'
});
// or UsersDocument.factory(...)
console.log(user);
// saving document
await users.save(user);
}
main();
```
##### Safe merging
When you need update a document you can use
safe document merging:
```ts
# document-safe-merging.ts
import {Repository} from 'mongot';
import {UserCollection} from './UserCollection';
const repository = new Repository('mongodb://localhost/test', {});
async function main(): void {
const users: UserCollection = repository.get(UserCollection);
const user = users.findOne();
user.merge({lastName: 'Bond'});
// save changes
users.save(user);
}
main();
```
This method saves data described in document schema only.
#### Read queries
Get connected collection to execute find query over:
```ts
# find.ts
import {Repository} from 'mongot';
import {UserCollection} from './UserCollection';
const repository = new Repository('mongodb://localhost/test', {});
async function main(): void {
const users: UserCollection = repository.get(UserCollection);
const user = await users.findByEmail('username@example.com');
console.log(user);
}
main();
```
You can use any of these `Collection` methods for
querying: `findOne`, `find` and `aggregate` (see specs for help).
#### Write queries
```ts
# update.ts
import {Repository, ObjectID} from 'mongot';
import {UserCollection} from './UserCollection';
const options = {};
const repository = new Repository('mongodb://localhost/test', options);
async function main(): void {
const users: UserCollection = repository.get(UserCollection);
const user = await users.findOne();
user.updated = new Date();
users.save(user);
}
main();
```
`Collection` method `save` saves any data for `DocumentSchema` types.
You also can use these `Collection` methods:
`updateOne`, `findOneAndUpdate`, `updateMany` (see specs for help);
#### Partial
You can use projection and aggregation with partial schemas:
```ts
# partial.ts
import {PartialDocumentFragment, prop} from 'mongot';
import {UserCollection} from './UserCollection';
// initialize repo ...
@fragment
class PartialUser extends PartialDocumentFragment {
@prop email: strng;
@prop created: Date;
}
(async function() {
const Users = repository.get(UserCollection);
const partialUser = await (await Users.find())
.map(doc => PartialUser.factory(doc))
.project<PartialUser>({email, created})
.fetch();
console.log(partialUser instanceof PartialDocumentFragment); // true
)();
```
#### Virtual getter
You can mark a schema getter by `@virtual` decorator if you want to
serialize the getter value with `toJSON()` or `toObject()`.
Example
```ts
@document
class UserDocument extends SchemaDocument {
@prop firstName: string;
@prop lastName?: string;
@virtual get displayName(): string {
return [this.firstName, this.lastName]
.filter(x => !!x)
.join(' ')
}
}
const user = new UserDocument({firstName: 'User', lastName: 'Name'});
console.log(JSON.stringify(user));
```
you'll get
```json
{
"firstName": "User",
"lastName": "Name",
"displayName": "User Name"
}
```
## License
MIT