Acessando o MongoDB usando Typescript

Olá pessoal,

Continuando nossa série de artigos sobre Typescript e desenvolvimento com Visual Studio Code, hoje iremos abordar como acessar o MongoDB usando Typescript. Anteriormente já abordamos como criar aplicações JavaScript com Typescript e também como desenvolver aplicações com Angular2 e Typescript. E em todos os artigos estamos usando o Visual Studio Code, um editor multiplataforma disponível para Windows, Linux e Mac OS X. Para saber mais, preparamos também um artigo que fala mais especificamente sobre o Visual Studio Code.

Se desejar, você pode obter no GitHub do TalkitBR o código completo do projeto desenvolvido nesse artigo .

Mas antes de começarmos a discorrer sobre o assunto do nosso artigo, vale a pena descrever brevemente o que é o MongoDB.

O MongoDB é um banco de dados NoSQL orientado a documentos, de código aberto e que possui como características alto desempenho, alta disponibilidade e escalabilidade automática. Ele possui os chamados esquemas dinâmicos (conhecidos como BSON) permitindo que as informações sejam armazenadas de forma natural, podendo ser aninhadas em hierarquias de documentos. Isso tudo sem perder seu desempenho. E por trabalhar com documentos JSON, que são representações de objetos JavaScript, ele se encaixa perfeitamente em aplicações nessas aplicações. Por isso acaba sendo uma das opções mais adotadas para armazenar dados de aplicações desenvolvidas com JavaScript. Temos, por exemplo, o chamado MEAN que é o desenvolvimento de toda a aplicação usando a linguagem JavaScript através do MongoDB, ExpressJS, Angular e Node.JS.

E nesse contexto, temos o Typescript que, conforme abordado no nosso artigo “Crie aplicações JavaScript com TypeScript no Visual Studio Code”, permite escrever JavaScript, sem ter que lidar com problemas comuns como ausência explícita de tipos e também erros do JavaScript em tempo de execução.

Preparando o Ambiente

Como já descrito anteriormente, vamos usar o Visual Studio Code. Se você ainda não tem ele instalado, baixe e instale agora mesmo.

Precisaremos também ter instalado o Node.JS que pode ser baixado no site https://nodejs.org/en/download/.

Depois de instalado o Node.JS, certifique-se que o seu Visual Studio Code possui a extensão NPM necessária para baixarmos os pacotes NPM dentro do nosso projeto. Para instalar essa extensão, abra o Visual Studio Code, pressione code>CTRL + P e execute o seguinte comando: ext install vscode-npm.

Precisamos também ter um servidor MongoDB para armazenarmos as informações. Se você tiver acesso a um servidor MongoDB, basta obter endereço do servidor. Mas se não tiver, não se preocupe. Baixe e instale o MongoDB na sua própria máquina de desenvolvimento. Você pode também usar o MongoDB direto da nuvem, como por exemplo, o Microsoft Azure e o Amazon EC2 (para saber mais acesse o link “Hands-on: Deploying MongoDB on Azure”).

Por fim, precisamos inicializar o servidor do MongoDB. Se estamos rodando o servidor na máquina local, basta executarmos o mongod que pode ser localizado nos binários da pasta onde foi instalado o MongoDB. Exemplo:

C:\Program Files\MongoDB\Server\3.2\bin>mongod –dbpath c:\data

O argumento dbpath permite definir o caminho onde serão armazenados os dados e é necessário somente na primeira execução.

Criando o projeto no Visual Studio Code

Para criarmos um novo projeto no Visual Studio Code, basta criarmos uma nova pasta vazia e abri-la diretamente no Visual Studio Code.

Execute o Visual Studio Code e então abra uma pasta vazia. Exemplo: mongodbTS. Antes de começarmos a desenvolver o código da nossa aplicação, vamos começar incluindo o arquivo package.json para especificar os módulos NPM que precisaremos usar no nosso projeto.

Usando o Visual Studio Code, crie o arquivo package.json na raiz do projeto e nele escreva inicialmente o seguinte conteúdo:

package.json

{
    "name": "mongodb-ts",
    "version": "1.0.0",
    "dependencies": {
        "mongodb": "2.1.16",
        "mongoose": "4.4.12"
    },
    "devDependencies": {
        "typescript": "1.8.10",
        "typings": "0.7.12"
    }
}
  • Estamos especificando neste arquivo as dependências de desenvolvimento e as dependências para execução do projeto.
  • Para desenvolvimento, estamos adicionando os pacotes typescript e typings que nos permitirão desenvolver o aplicativo com Typescript. O Typings permitirá incluir definições de tipos dentro do projeto.
  • Já para execução do projeto estamos especificando o pacote mongoose. Esse pacote possui recursos que facilitam o acesso as informações do MongoDB (temos também o pacote mongodb que é uma dependência do mongoose. Para saber mais sobre o mongoose, acesso o link http://mongoosejs.com/.

Feito isso, vamos executar o comando de instalação dos pacotes NPM. Pressione a tecla F1 e execute o seguinte comando: npm: install. Os pacotes NPM serão instalados no nosso projeto:

acessando_mongodb_usando_ts_packagesjson

Próximo passo é incluirmos os arquivos de configuração do typings e do typescript:

typings.json

{
  "ambientDependencies": {
    "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#6697d6f7dadbf5773cb40ecda35a76027e0783b2",    
    "mongodb": "github:DefinitelyTyped/DefinitelyTyped/mongodb/mongodb.d.ts#3cf5221c92ba0cef413449fb4fb2fd1ffbfbcfbf",
    "mongoose": "github:DefinitelyTyped/DefinitelyTyped/mongoose/mongoose.d.ts#56295f5058cac7ae458540423c50ac2dcf9fc711",
    "node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#aee0039a2d6686ec78352125010ebb38a7a7d743"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules",
    "typings/browser.d.ts",
    "typings/browser"    
  ]
}

O tsconfig.json define configurações do projeto para que o mesmo seja compilado pelo Typescript. Podemos agora adicionar scripts no arquivo package.json para que executem tanto o typings como o Typescript no nosso projeto:

package.json

{
    "name": "mongodb-ts",
    "version": "1.0.0",
    "scripts": {
        "start": "npm run tsc:w",    
        "tsc": "tsc",
        "tsc:w": "tsc -w",
        "typings": "typings",
        "postinstall": "typings install" 
    },
    "dependencies": {
        "mongodb": "2.1.16",
        "mongoose": "4.4.12"
    },
    "devDependencies": {
        "typescript": "1.8.10",
        "typings": "0.7.12"
    }
}

Vamos agora executar o comando de instalação do NPM. Pressione a tecla F1 e execute o seguinte comando: npm: install. O script typings será executado e os tipos especificados no arquivo typings.json serão baixados:

acessando_mongodb_usando_ts_packagesjson_typingsrun

Pronto! O projeto está criado. Agora vamos começar a desenvolver a nossa aplicação.

Desenvolvendo Typescript para acessar o MongoDB

Para demonstrar o uso do MongoDB, vamos armazenar informações de cálculo de IMC de pessoas. Teremos um documento que descreve a pessoa, com informações como nome, gênero e data de nascimento, e outro documento com as informações de peso, altura e data de medição.

Para organizar melhor o código, crie uma pasta db. Nessa pasta crie os seguintes arquivos:

IBodyMassIndex.ts

import mongoose = require('mongoose');

interface IBodyMassIndex extends mongoose.Document {
    _id: mongoose.Types.ObjectId;
    weight: number;
    stature: number;    
}

export = IBodyMassIndex

IPerson.ts

import mongoose = require('mongoose');
import IBodyMassIndex = require('./IBodyMassIndex');

interface IPerson extends mongoose.Document {
    _id: mongoose.Types.ObjectId;
    name: string;
    gender: string;
    birthdate: Date;
    bmiList: IBodyMassIndex[];
}

export = IPerson;

Note que a propriedade bmiList é um array de documentos IBodyMassIndex.

Vamos agora compilar esses arquivos. Pressione a tecla F1 e então escreva npm: run script. Serão mostrados os scripts definidos no arquivo package.json. Selecione o script tsc. O código deverá ser compilado sem problemas. Caso tenha ocorrido algum erro, revise os passos anteriores:

acessando_mongodb_usando_ts_packagesjson_tscrun

Outra opção é executar o script tsc:w que irá monitorar os arquivos .ts do projeto, executando o tsc a qualquer sinal de mudança.

Vamos dar prosseguimento. O próximo passo é criar o schema dos dados de IPerson e IBodyMassIndex.

BodyMassIndex.ts

import mongoose = require('mongoose');
import IBodyMassIndex = require('./IBodyMassIndex');

var bodyMassIndexSchema = new mongoose.Schema({
    weight: { type: Number, required: true },
    stature: { type: Number, required: true }
}, { 
    toJSON: {
        virtuals: true 
    }
});

/* Returns the bmi based on weight and stature */
bodyMassIndexSchema.virtual('bmi').get(function() {
    return this.weight / Math.pow(this.stature, 2);
});

var BodyMassIndex = mongoose.model<IBodyMassIndex>('BodyMassIndex', bodyMassIndexSchema);

export = BodyMassIndex;

Note que especificamos na criação do Schema que as propriedades virtuais sejam expostas no resultado JSON do documento. Dessa forma conseguiremos obter o valor do atributo bmi.

Person.ts

import mongoose = require('mongoose');
import IPerson = require('./IPerson');
import IBodyMassIndex = require('./IBodyMassIndex');

var personSchema = new mongoose.Schema({
    name: { type: String, required: true },
    gender: { type: String },
    birthdate: { type: Date },
    bmiList: [{ type: mongoose.Schema.Types.ObjectId, ref: 'BodyMassIndex' }]
});

var Person = mongoose.model<IPerson>('Person', personSchema);

export = Person;

Observe que temos uma propriedade do documento Person, o bmiList, que é um array de Ids que referenciam o documento BodyMassIndex. Dessa forma conseguimos relacionar um documento com o outro. Esse recurso é disponibilizado pelo schema do Mongoose.

Pronto! Podemos ainda criar um outro arquivo Typescript para facilitar acesso a esses modelos. Esse arquivo irá criar a conexão com o MongoDB e disponibilizar funções para obter as informações:

Model.ts

import mongoose = require('mongoose');
import IBodyMassIndex = require('./IBodyMassIndex');
import BodyMassIndex = require('./BodyMassIndex');
import IPerson = require('./IPerson');
import Person = require('./Person');

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

export function getPerson(id: string, callback: (person: IPerson) => void) {
    Person.findById(id).populate("bmiList").exec(function (error, person) {
        if (error) {
            console.error(error); return;
        }
        
        callback(person);
    });
}

export function getPersonList(callback: (personList: IPerson[]) => void) {
    var query = {};
    Person.find(query).populate('bmiList').exec(function(error, personList) {
        if(error) {
            console.error(error); return; 
        }
        
        callback(personList);
    });
}

A função populate instrui o mongoose a obter as informações da propriedade com base na referência ao documento especificado no document.

Vamos compilar os arquivos Typescript para garantir que o código está correto. Pressione a tecla F1 e então escreva npm: run script. Serão mostrados os scripts definidos no arquivo package.json. Selecione o script tsc. O código deverá ser compilado sem problemas. Caso tenha ocorrido algum erro, revise os passos anteriores.

Desenvolvendo a aplicação que irá acessar os dados do MongoDB

O próximo e último passo é criar a aplicação que irá acessar os arquivos que acabamos de criar.

Crie na raiz do projeto do Visual Studio Code o arquivo app.ts. Nele vamos colocar o código para acessar os arquivos .ts que criamos agora a pouco:

app.ts

import mongoose = require("mongoose");
import db = require("./db/model");
import BodyMassIndex = require("./db/BodyMassIndex");
import Person = require("./db/Person");

console.log("creating person");

var person = new Person({ name: "Smith", gender: "Male", birthdate: new Date(1970, 4, 20)});

var bmi;
bmi = new BodyMassIndex({ weight: 73.8, stature: 1.8 });
bmi.save();
person.bmiList.push(bmi._id);

bmi = new BodyMassIndex({ weight: 79.5, stature: 1.8 });
bmi.save();
person.bmiList.push(bmi._id);

bmi = new BodyMassIndex({ weight: 71.7, stature: 1.8 });
bmi.save();
person.bmiList.push(bmi._id);
    
person.save(function(error, person) {
    if (error) {
        console.error(error);
        process.exit(1);
    }
    
    console.log("listing person");
    db.getPersonList(function(personList) {
        console.log(JSON.stringify(personList, null, "\t"));
        process.exit(0);
    });   
});

Feito isso, vamos agora compilar os arquivos no projeto. Pressione a tecla F1 e então escreva npm: run script. Serão mostrados os scripts definidos no arquivo package.json. Selecione o script tsc. O código deverá ser compilado sem problemas. Caso tenha ocorrido algum erro, revise os passos anteriores.

Agora chegou o momento de executar nossa aplicação no Visual Studio Code. Pressione a tecla F5 iniciar a execução. Caso seja a primeira execução, será solicitada a configuração do arquivo de launch. Nesse caso, selecione a opção Node.JS e pronto. O Visual Studio Code irá fornecer um arquivo de launch padrão. Vamos alterá-lo para ter o seguinte arquivo:

launch.json

{
	"version": "0.2.0",
	"configurations": [
		{
			"name": "Launch",
			"type": "node",
			"request": "launch",
			"program": "${workspaceRoot}\\app.js",
			"stopOnEntry": false,
			"args": [],
			"cwd": "${workspaceRoot}",
			"preLaunchTask": null,
			"runtimeExecutable": null,
			"runtimeArgs": [
				"--nolazy"
			],
			"env": {
				"NODE_ENV": "development"
			},
			"externalConsole": false,
			"sourceMaps": true,
			"outDir": null
		},
		{
			"name": "Attach",
			"type": "node",
			"request": "attach",
			"port": 5858,
			"address": "localhost",
			"restart": false,
			"sourceMaps": false,
			"outDir": null,
			"localRoot": "${workspaceRoot}",
			"remoteRoot": null
		}
	]
}

Depois de configurado o arquivo launch.json, basta pressionar novamente a tecla F5 para executar a aplicação. E o resultado será exibido no Console do Visual Studio Code.

acessando_mongodb_usando_ts_final

Você ainda pode fazer depuração do código executando os arquivos Typescript, linha a linha. Para tanto, basta incluir breakpoints nas linhas que desejar.

E terminamos. Se desejar, você pode obter o código completo desse projeto no GitHub do TalkitBR. Mande também seus comentários e dúvidas. E continue nos acompanhando no talkitbr.

Abraços!

Referências:

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s