Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Douglas

Migrando base existente para um NoSQL

Recommended Posts

Qual seria a melhor forma de migrar de banco de dados relacional para um NoSQL?

 

Por exemplo já possuo um banco de dados Mysql e muitos registros.

 

Existem ferramentas para auxiliar nesse processo? Ou vai na raça mesmo, scripts para popular a tabela e ponto? :)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Qual seria a melhor forma de migrar de banco de dados relacional para um NoSQL?

Por exemplo já possuo um banco de dados Mysql e muitos registros.

 

Olha Douglas,

 

Meu ponto de vista é que, por se tratar de um conceito diferente, a migração requer, em primeira instância, uma nova modelagem do banco de dados.

 

Veja a modelagem abaixo para um sistema de imóveis:

 

Imagem Postada

 

Neste modelo relacional os dados estariam assim:

 

mysql> SELECT * FROM `Atributo`;
+------------+--------------+
| idAtributo | atributoNome |
+------------+--------------+
| 	1 | Banheiro 	|
| 	2 | Copa 	|
| 	3 | Cozinha 	|
| 	4 | Quarto 	|
| 	5 | Sala 	|
+------------+--------------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM `Bairro`;
+----------+----------+------------+
| idBairro | idCidade | bairroNome |
+----------+----------+------------+
| 	1 | 	1 | Centro 	|
+----------+----------+------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM `Cidade`;
+----------+------------+
| idCidade | cidadeNome |
+----------+------------+
| 	1 | Franca 	|
+----------+------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM `Imovel`;
+----------+----------+------------+------------------+
| idImovel | idBairro | imovelDono | imovelEndereco |
+----------+----------+------------+------------------+
| 	1 | 	1 | Fulano 	| Rua dos bobos, 0 |
+----------+----------+------------+------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM `ImovelAtributo`;
+------------------+----------+------------+---------------------+
| idImovelAtributo | idImovel | idAtributo | imovelAtributoValor |
+------------------+----------+------------+---------------------+
| 	1 | 	1 | 	1 | 4 	|
| 	2 | 	1 | 	2 | 1 	|
| 	3 | 	1 | 	3 | 1 	|
| 	4 | 	1 | 	4 | 3 	|
| 	5 | 	1 | 	5 | 3 	|
+------------------+----------+------------+---------------------+
5 rows in set (0.00 sec)

Para saber os atributos de um imóvel:

 

mysql> SELECT `i`.`idImovel`,`i`.`imovelEndereco`,`b`.`bairroNome`,`c`.`cidadeNome`,`a`.`atributoNome`,`ia`.`imovelAtributoValor` AS `quantidade`
	-> FROM `Atributo` AS `a`
	-> LEFT JOIN `ImovelAtributo` AS `ia` USING(`idAtributo`)
	-> LEFT JOIN `Imovel` AS `i` USING(`idImovel`)
	-> LEFT JOIN `Bairro` AS `b` USING(`idBairro`)
	-> LEFT JOIN `Cidade` AS `c` USING(`idCidade`);
+----------+------------------+------------+------------+--------------+------------+
| idImovel | imovelEndereco | bairroNome | cidadeNome | atributoNome | quantidade |
+----------+------------------+------------+------------+--------------+------------+
| 	1 | Rua dos bobos, 0 | Centro 	| Franca 	| Banheiro 	| 4 	|
| 	1 | Rua dos bobos, 0 | Centro 	| Franca 	| Copa 	| 1 	|
| 	1 | Rua dos bobos, 0 | Centro 	| Franca 	| Cozinha 	| 1 	|
| 	1 | Rua dos bobos, 0 | Centro 	| Franca 	| Quarto 	| 3 	|
| 	1 | Rua dos bobos, 0 | Centro 	| Franca 	| Sala 	| 3 	|
+----------+------------------+------------+------------+--------------+------------+
5 rows in set (0.00 sec)

Como pode ver, a tabela de atributos resolve um problema que temos no modelo relacional. Só que esse problema não existe no no modelo não relacional, seja o banco de dados orientado a documentos ou a colunas, você pode todos os atributos do imóvel, no próprio imóvel.

 

Então, antes de migrar uma base SQL para um MongoDB, CouchDB ou Cassandra, é interessante revisar a modelagem.

 

;)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Já pensei nisso.

 

A modelagem irá mudar mesmo, e o conceito de não ter um schema pré-definido vai me ajudar muito nessa aplicação, porque ela sempre vai possuir novas informações.

 

 

Mas o meu maior problema agora é migrar os dados existentes para o NoSQL. Como as empresas fazem para migrar de bancos de dados relacional para NoSQL? Criar scripts para realizar os inserts no banco NoSQL?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Eu ja criei um script para isso, porem ele mantem o mesmo esquema do SQL então não serve mto para aplicacoes reais, fiz mais oara testes mesmo. Mas se quiser: http://imasters.com.br/artigo/17078/bancodedados/como_converter_mysql_para_mongodb/

Compartilhar este post


Link para o post
Compartilhar em outros sites

No caso vai precisar ser na raça a mudança de banco.

 

Não necessariamente, Douglas...

 

Talvez por eu ser uma pessoa sedentária, só de pensar em alguém fazendo "escalada de montanha" já me cansa, hehehhe

 

Então, vamos pensar no seguinte:

 

Você tem 2 problemas:

 

1. Mapear um modelo Relacional para Objetos.

2. Mapear Objetos para um modelo de Documentos.

 

Como toda solução demanda necessariamente de um estudo do problema, vamos começar tentando entender o problema:

 

Imagem Postada

 

Devido às características do modelo relacional, precisamos de tabelas auxiliares em praticamente todo o domínio, mapear esse modelo para objetos é simples e existem várias técnicas para isso.

 

Mas o nosso problema não restringe-se à apenas mapear esse modelo para objetos; De fato, precisamos modificar essa modelagem em tempo de execução, precisamos converter nosso modelo relacional para um orientado a documentos (ou colunas).

 

Como esse tópico tende a se tornar bastante complexo quanto a teoria, vou deixar aqui algumas perguntas antes de prosseguir:

 

Como essas tabelas se relacionam ?

Onde estão as associações, agregações e composições nesse modelo específico ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Era isso q estava falando com o neto agora mas ainda não sei se o mais correto, mas eu faria um script para buscar as infos das FKs das tabelas e geraria array interno da collection no NOSQL.

 

Exemplo: Pessoa chama tabela telefone, end, cidade, UF

 

no NOSQL ficaria

 

Pessoa{

nome: 'Eu mesmo';

telefone{ tel: 8888888},

end{ rua: 'Blablabla'},

cidade{ cidade: 'Sao Paulo'},

UF{ uf: 'SP'}

}

 

Manja?

Compartilhar este post


Link para o post
Compartilhar em outros sites

mas eu faria um script para buscar as infos das FKs das tabelas e geraria array interno da collection no NOSQL.

Isso seria problemático Jean,

 

Imagina que tenhamos uma estrutura similar a dos imóveis, ilustrada POST #2.

 

Se pegarmos as relações conforme estão no modelo relacional, continuaremos tendo uma coleção para os atributos e os atributos dos imóveis e não queremos isso, afinal, isso é uma solução para um modelo relacional mas não precisamos disso em um modelo orientado a documentos.

 

Precisamos identificar as associações, agregações e composições para somente então mapear de relacional para documentos, somente com a identificação dos tipos de associações que seremos capazes de decidir o que deve ser propriedade do documento, o que deve ser uma referência e o que deve ser uma agregação ou composição.

 

:D

 

PS: Para quem faltou às aulas sobre UML e não está entendendo sobre o que estou falando http://forum.imasters.com.br/public/style_emoticons/default/seta.gif UML

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bora no RDM entao neh ;D

Compartilhar este post


Link para o post
Compartilhar em outros sites

Então vamos pensar nos relacionamentos:

 

Imagem Postada

 

Bom, temos três tipos de relações:

 

 

Associação:

 

Como pode-se ver, tanto no caso de UserGroup quanto no ProductCategory, temos uma tabela que relaciona um Usuário à um grupo ou um Produto à uma categoria; Podemos chamas essa associação de Link e é através desse link que sabemos, no modelo relacional, que um usuário pertence à um grupo ou um produto à uma categoria ou diversas outras situações.

 

É notório também que temos uma multiplicidade [1] para User e para Group e uma multiplicidade de [1..*] para UserGroup, isso indica que que nossa UserGroup poderá conter um número N de grupos para 1 único usuário ou que N usuários podem estar em 1 mesmo grupo; O mesmo ocorre para Product, Category e ProductCategory.

 

A grande ponto é que as tabelas UserGroup e ProductCategory são desnecessárias em um modelo OD e não devemos migrá-la para o novo banco de dados, então fica a questão:

 

Devemos ter uma coleção específica para os grupos e categorias ?

  • Existirão grupos ou categorias suficiente para que se justifique uma coleção para eles ?
  • Os dados referentes aos grupos ou categorias são tão voláteis; Eles são modificados tão constantemente a ponto de justificar uma coleção específica para eles ?
Como a resposta para as duas perguntas acima variam de acordo com cada caso, não é possível decidir na própria aplicação o que fazer com esse tipo de relacionamento, cada caso é um caso e deveremos abstrair a solução.

 

 

Agregação:

 

Identificar as agregações é muito simples, basta fazermos a seguinte pergunta:

 

"Se destruirmos o participante X, o participante Y é destruído também ?"

 

Se o participante Y for independente do participante X e possuir suas próprias regras, então trata-se de agregação, por exemplo:

 

Se rasgarmos um pedido, os produtos da loja são destruídos ou o cliente morre ?

 

Fica claro nesse ponto que temos coleções específicas para um Consumidor, Pedido e Produto.

 

Temos diversos pedidos em uma loja.

Uma loja possui vários produtos.

Vários clientes podem fazer pedidos na loja.

 

 

Composição:

 

A mesma pergunta feita para identificar as agregações, pode ser feita para identificar uma composição:

 

"Se rasgarmos o pedido, os itens do pedido são destruídos ?"

 

Perceba que não estamos falando dos produtos e sim da lista que compõe um pedido; De fato, se rasgarmos o pedido, a lista é perdida.

 

Um outro caso é o do modelo de imóveis, se destruirmos a casa, os quartos, sala, cozinha e banheiro são destruídos ?

 

Nessa situação, os itens do pedido podem ser uma matriz na coleção pedido e "quarto, sala, cozinha" podem ser propriedades do documento Imóvel.

 

Não precisamos de coleções para esses casos.

 

 

Problema:

1. Tipos de associações diferentes demandam soluções diferentes.

2. Mesmo tipo de associação pode demandar soluções diferentes em uma mesma modelagem.

 

 

Mesmo com heurística, a aplicação não conseguirá identificar por si só o que fazer para mudar a modelagem; Se tentarmos prever todos os casos em um único algorítimo, teremos código demais, não reutilizável, difícil de manter e ainda assim, não conseguiremos fechar todos os casos.

 

 

Solução:

Precisamos abstrair os algorítimos.

 

Alguém tem alguma sugestão ?

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Creio q os grupos e categorias deveriam estar dentro da coleçao dos produtos/pedidos e usuarios, e utilizarmos o map/reduce como você mesmo demonstrou anteriormente.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Creio q os grupos e categorias deveriam estar dentro da coleçao dos produtos/pedidos e usuarios,

 

Certo, mas você está focado nesse problema específico.

 

Vamos mudar o domínio, vamos pensar que não temos produtos ou pedidos; Temos escolas, instrutores, alunos, provas.

 

A ferramenta deve ser reutilizável o suficiente para funcionar com qualquer domínio.

 

e utilizarmos o map/reduce como você mesmo demonstrou anteriormente.

 

A não ser que implementemos um MapReduce para um banco de dados relacional, não conseguiremos utilizá-lo em um MySQL migrar seus dados

Compartilhar este post


Link para o post
Compartilhar em outros sites

nao seria para migrar mas sim para retornar, mas beleza depois pensamos nisso.

 

Creio assim q seria interessante um teste de pegar as tabelas q nao possuem FK, seriam as infos q complementam as tabelas e ir puxando elas ateh a tabela pai e ver oq da, creio q esse aproach ja ajuda bastante, mas precisamos de exemplos para testar.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Creio assim q seria interessante um teste de pegar as tabelas q nao possuem FK

 

Certo, vamos pensar então que precisamos migrar uma base MySQL MyISAM.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ah tua ideia eh pegar e mapear mesmo? Sem algo mais padronizado. Pois entao peguei uma base ridicula para trabalhar, tabelas com mais de 60 campos e SEM PK! Entao a ideia seria falar qual a atbela paie quais as ligam, mas e como identificar seus relacionamentos?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Acho que poderíamos montar alguns exemplos de modelagens reais, pra realizar testes.

 

- Imóveis

- loja online

- fórum

- ... ideias?

 

(bases para testes iniciais, depois vamos para bases reais)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vamos pegar um eskema de ecomemrce entao q possui produtos, usuarios, pedidos, categorias, fornecedores e cia

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ok pessoal, vamos pensar em uma situação simples para começar:

 

CREATE TABLE `exemplo`.`Log` (
`idLog` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT ,
`logAction` SET('CREATE','READ','UPDATE','DELETE') NOT NULL ,
`logUser` VARCHAR(45) NOT NULL ,
`logTimestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`logSection` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`idLog`)
);

 

Alguns dados:

INSERT INTO `exemplo`.`Log` (`logAction`, `logUser`, `logSection`) VALUES ('CREATE', 'neto', 'Category');
INSERT INTO `exemplo`.`Log` (`logAction`, `logUser`, `logSection`) VALUES ('CREATE', 'neto', 'Product');
INSERT INTO `exemplo`.`Log` (`logAction`, `logUser`, `logSection`) VALUES ('DELETE', 'neto', 'Product');
INSERT INTO `exemplo`.`Log` (`logAction`, `logUser`, `logSection`) VALUES ('READ', 'neto','Product');

 

Resultado:

 

mysql> SELECT * FROM `Log`;
+-------+-----------+---------+---------------------+------------+
| idLog | logAction | logUser | logTimestamp 	| logSection |
+-------+-----------+---------+---------------------+------------+
| 	1 | CREATE	| neto	| 2010-09-02 06:24:11 | Category |
| 	2 | CREATE	| neto	| 2010-09-02 06:24:11 | Product	|
| 	3 | DELETE	| neto	| 2010-09-02 06:24:11 | Product	|
| 	4 | READ 	| neto	| 2010-09-02 06:24:11 | Product	|
+-------+-----------+---------+---------------------+------------+
4 rows in set (0.00 sec)

A tabela de Log é bem simples e um documento para ela seguiria a mesma estrutura:

 

Imagem Postada

 

Mesmo abstraindo o tipo de documento, a estrutura lógica fica bastante simples:

 

Imagem Postada

 

O padrão Builder é bastante interessante para esse caso, conseguimos construir um documento parte por parte e ainda abstraído. Isso significa que tanto faz se vamos criar um documento para MongoDB, CouchDB ou qualquer outro banco de dados orientado a documentos.

 

Toda a lógica para criação do documento ficará encapsulada e nosso Director utilizará apenas os métodos de interface do seu próprio builder, vamos ver como ficaria:

 

rdm/core/document.php

<?php
/**
* Interface para criação de um documento
*/
interface Document {
/**
 * Adiciona uma nova propriedade ao documento
 * @param $property Property
 * @return Property
 */
public function addProperty( Property $property );

/**
 * Salva e retorna o novo documento
 * @return array
 */
public function save();
}

 

rdm/core/DocumentBuilder.php

<?php
/**
* Interface para criação de um Builder que construirá o documento parte por parte
*/
interface DocumentBuilder {
/**
 * Cria uma propriedade que possui um valor embutido
 *
 * @param $name string Nome da propriedade
 * @param $values array Matriz contendo os valores que serão embutidos
 * @return Property
 */
public function buildEmbeddedProperty( $name , array $values );

/**
 * Cria uma propriedade que possui uma referência à um documento de outra coleção
 *
 * @param $name string Nome da propriedade
 * @param $reference Coleção que conterá o documento que será utilizado na referência
 * @param $value mixed Valor da propriedade
 * @return Property
 */
public function buildReferencedProperty( $name , $reference , $value );

/**
 * Cria uma propriedade simples, com valor literal
 *
 * @param $name string Nome da propriedade
 * @param $value mixed Valor da propriedade
 * @return Property
 */
public function buildSimpleProperty( $name , $value );

/**
 * Recupera o documento criado
 *
 * @return Document
 */
public function getDocument();
}

 

rdm/core/DocumentDirector.php

<?php
/**
* Interface para criação de um Director que deverá iterar a estrutura de dados e criar os documentos
*/
interface DocumentDirector {
/**
 * Converte o modelo relacional para documentos
 */
public function convert();

/**
 * Recupera um iterator para os documentos
 * @return Iterator
 */
public function getDocuments();
}

 

core/core/Property.php

<?php
/**
* Interface para criação de uma propriedade de um documento
*/
interface Property {
/**
 * Recupera o nome da propriedade
 * @return string
 */
public function getName();

/**
 * Recupera o valor da propriedade
 * @return mixed
 */
public function getValue();
}

 

Com as interfaces definidas, vamos para a implementação no MongoDB:

 

rdm/mongo/properties/AbstractMongoProperty.php

<?php
require_once 'rdm/core/Property.php';

/**
* Implementação base de uma propriedade, para facilitar na criação de outras propriedades
*/
abstract class AbstractMongoProperty implements Property {
/**
 * Nome da propriedade
 * @var string
 */
protected $name;

/**
 * Valor da propriedade
 * @var mixed
 */
protected $value;

/**
 * Cria uma nova propriedade
 *
 * @param $name string Nome da propriedade
 * @param $value mixed Valor da propriedade
 */
public function __construct( $name , $value ){
	$this->name = $name;
	$this->value = $value;
}

/**
 * Recupera o nome da propriedade
 * @return string
 * @see rdm/core/Property::getName()
 */
public function getName(){
	return $this->name;
}
}

 

rdm/mongo/properties/MongoEmbeddedProperty.php

<?php
require_once 'rdm/mongo/properties/AbstractMongoProperty.php';

/**
* Implementação de uma propriedade que possui um valor embutido
*/
class MongoEmbeddedProperty extends AbstractMongoProperty {
/**
 * Cria o objeto da propriedade
 *
 * @param $name string Nome da propriedade
 * @param $values array Lista de valores da propriedade
 */
public function __construct( $name , array $values ){
	parent::__construct( $name , $values );
}

/**
 * Adiciona um novo valor à propriedade
 *
 * @param $value mixed O valor que será adicionado à propriedade
 */
public function addValue( $value ){
	$this->value[] = $value;
}

/**
 * Recupera os valores da propriedade
 * @return array
 * @see rdm/core/Property::getValue()
 */
public function getValue(){
	$values = array();

	foreach ( $this->value as $value ){
		if ( $value instanceof Property ){
			$value = $value->getValue();
		}

		$values[] = $value;
	}

	return $values;
}
}

 

rdm/mongo/properties/MongoLiteralProperty.php

<?php
require_once 'rdm/mongo/properties/AbstractMongoProperty.php';

/**
* Implementação de uma propriedade com valor literal
*/
class MongoLiteralProperty extends AbstractMongoProperty {
/**
 * Constroi a propriedade
 *
 * @param $name string Nome da propriedade
 * @param $value mixed Valor da propriedade
 */
public function __construct( $name , $value ){
	if ( gettype( $value ) == 'array' ){
		throw new InvalidArgumentException( 'Para arrays utilize MongoEmbeddedProperty' );
	}

	$this->name = $name;
	$this->value = $value;
}

/**
 * Recupera o valor da propriedade
 * @return mixed
 * @see rdm/core/Property::getValue()
 */
public function getValue(){
	return $this->value;
}
}

 

rdm/mongo/properties/MongoReferencedProperty.php

<?php
require_once 'rdm/mongo/MongoDocument.php';
require_once 'rdm/mongo/properties/AbstractMongoProperty.php';

/**
* Implementação de uma propriedade que possui referência à um documento de outra coleção
*/
class MongoReferencedProperty extends AbstractMongoProperty {
/**
 * Coleção que conterá o documento referenciado
 * @var MongoCollection
 */
private $collection;

/**
 * Constroi a propriedade
 *
 * @param $collection MongoCollection A coleção que conterá a propriedade
 * @param $name string Nome da propriedade
 * @param $value mixed Valor da propriedade
 */
public function __construct( MongoCollection $collection , $name , $value ){
	parent::__construct( $name , $value );

	$this->value = new MongoDocument( $collection );
	$this->collection = $collection;

	if ( gettype( $value ) == 'array' ){
		$this->addProperty( new MongoEmbeddedProperty( $name , $value ) );
	} else {
		$this->addProperty( new MongoLiteralProperty( $name , $value ) );
	}
}

/**
 * Adiciona uma nova propriedade ao documento de referência
 *
 * @param $property Property A nova propriedade que será adicionada ao documento
 * @return Property
 */
public function addProperty( Property $property ){
	return $this->value->addProperty( $property );
}

/**
 * Recupera o valor da propriedade
 * @return array
 * @see rdm/core/Property::getValue()
 */
public function getValue(){
	$doc = $this->value->save();

	return $this->collection->createDBRef( $doc );
}
}

 

E agora a implementação de um documento Mongo e seu Builder:

 

rdm/mongo/Mongodocument.php

<?php
require_once 'rdm/core/Document.php';

/**
* Implementação de um documento para o MongoDB
*/
class MongoDocument implements Document {
/**
 * Propriedades do documento
 * @var array
 */
private $properties = array();

/**
 * Coleção onde o documento deverá ser salvo
 * @var MongoCollection
 */
private $collection;

/**
 * Constroi o objeto do documento
 *
 * @param MongoCollection $collection
 */
public function __construct( MongoCollection $collection ){
	$this->collection = $collection;
}

/**
 * Adiciona uma nova propriedade ao documento
 * @return Property
 * @see rdm/core/Document::addProperty()
 */
public function addProperty( Property $property ){
	$this->properties[ $property->getName() ] = $property;

	return $property;
}

/**
 * Salva o documento na coleção especificada
 * @return array
 * @see rdm/core/Document::save()
 */
public function save(){
	$document = array();

	foreach ( $this->properties as $name => $property ){
		$document[ $name ] = $property->getValue();
	}

	$this->collection->save( $document );

	return $document;
}
}

 

rdm/mongo/MongoDocumentBuilder.php

<?php
require_once 'rdm/core/DocumentBuilder.php';
require_once 'rdm/mongo/MongoDocument.php';
require_once 'rdm/mongo/properties/MongoEmbeddedProperty.php';
require_once 'rdm/mongo/properties/MongoLiteralProperty.php';
require_once 'rdm/mongo/properties/MongoReferencedProperty.php';

class MongoDocumentBuilder implements DocumentBuilder {
/**
 * Documento que será criado
 * @var Document
 */
private $document;

/**
 * Banco de dados que será utilizado para criação das coleções
 * @var string
 */
private $db;

/**
 * Instância do conector do Mongo
 * @var Mongo
 */
private $mongo;

/**
 * Constroi um novo Builder para criação de documentos para o MongoDB
 *
 * @param $mongo Mongo Instância do conector do Mongo
 * @param $db string Nome do banco de dados onde serão criadas as coleções
 * @param $collection string Nome da coleção que será criada
 */
public function __construct( Mongo $mongo , $db , $collection ) {
	$this->db = $db;
	$this->document = new MongoDocument( $mongo->selectCollection( $db , $collection ) );
	$this->mongo = $mongo;
}

/**
 * Cria uma propriedade que possui um valor embutido
 *
 * @param $name string Nome da propriedade
 * @param $values array Matriz contendo os valores que serão embutidos
 * @return Property
 */
public function buildEmbeddedProperty( $name , array $values ) {
	$property = new MongoEmbeddedProperty( $name , $values );

	return $this->document->addProperty( $property );
}

/**
 * Cria uma propriedade que possui uma referência à um documento de outra coleção
 *
 * @param $name string Nome da propriedade
 * @param $reference Coleção que conterá o documento que será utilizado na referência
 * @param $value mixed Valor da propriedade
 * @return Property
 */
public function buildReferencedProperty( $name , $reference , $value ) {
	$collection = $this->mongo->selectCollection( $this->db , $reference );
	$property = new MongoReferencedProperty( $collection , $name , $value );

	return $this->document->addProperty( $property );
}

/**
 * Cria uma propriedade simples, com valor literal
 *
 * @param $name string Nome da propriedade
 * @param $value mixed Valor da propriedade
 * @return Property
 */
public function buildSimpleProperty( $name , $value ) {
	$property = new MongoLiteralProperty( $name , $value );

	return $this->document->addProperty( $property );
}

/**
 * Recupera o documento criado
 *
 * @return Document
 */
public function getDocument() {
	return $this->document;
}
}

 

rdm/mongo/MongoDocumentDirector.php

<?php
require_once 'rdm/core/DocumentDirector.php';
require_once 'rdm/mongo/MongoDocumentBuilder.php';

/**
* Implementação de um Director que trabalhará com os dados do banco relacional e para criação os documentos
*/
class MongoDocumentDirector implements DocumentDirector {
/**
 * Nome da coleção que será utilizada para criação dos documentos
 * @var string
 */
private $collection;

/**
 * Iterator para os documentos criados
 * @var ArrayIterator
 */
private $documents;

/**
 * Nome do banco de dados que será utilizado para criação das coleções
 * @var string
 */
private $db;

/**
 * @var Mongo
 */
private $mongo;

/**
 * @var PDOStatement
 */
private $statement;

/**
 * Constroi um novo Director que trabalhará com os dados do banco relacional
 *
 * @param $statement PDOStatement
 * @param $mongo Mongo
 */
public function __construct( PDOStatement $statement , Mongo $mongo , $db , $collection ){
	$this->collection = $collection;
	$this->documents = new ArrayIterator();
	$this->db = $db;
	$this->statement = $statement;
	$this->mongo = $mongo;
}

/**
 * Converte o modelo relacional para documentos
 * @see rdm/core/DocumentDirector::convert()
 */
public function convert(){
	while ( ( $arr = $this->statement->fetch( PDO::FETCH_ASSOC ) ) !== false ){
		$builder = new MongoDocumentBuilder( $this->mongo , $this->db , $this->collection );

		foreach ( $arr as $key => $value ){
			$builder->buildSimpleProperty( $key , $value );
		}

		$this->documents->append( $builder->getDocument() );
	}

}

/**
 * Recupera um iterator para os documentos
 * @return Iterator
 * @see rdm/core/DocumentDirector::getDocuments()
 */
public function getDocuments(){
	return $this->documents;
}
}

 

Agora, usando isso ai:

 

$mysql = new PDO( 'mysql:host=127.0.0.1;dbname=exemplo' , 'mysqlUser' , 'mysqlPswd' );
$mongo = new Mongo( 'mongodb://mongoUser:mongoPswd@localhost' );

$director = new MongoDocumentDirector( $mysql->query( 'SELECT * FROM `Log`;' ) , $mongo , 'meudb' , 'logs' );

$director->convert();

foreach ( $director->getDocuments() as $document ){
$document->save();
}

 

 

O resultado disso será:

 

> use meudb;
switched to db meudb
> db.logs.find();
{ "_id" : ObjectId("4c7f8f197f8b9aa234000000"), "idLog" : "1", "logAction" : "CREATE", "logUser" : "neto", "logTimestamp" : "2010-09-02 06:24:11", "logSection" : "Category" }
{ "_id" : ObjectId("4c7f8f197f8b9aa234010000"), "idLog" : "2", "logAction" : "CREATE", "logUser" : "neto", "logTimestamp" : "2010-09-02 06:24:11", "logSection" : "Product" }
{ "_id" : ObjectId("4c7f8f197f8b9aa234020000"), "idLog" : "3", "logAction" : "DELETE", "logUser" : "neto", "logTimestamp" : "2010-09-02 06:24:11", "logSection" : "Product" }
{ "_id" : ObjectId("4c7f8f197f8b9aa234030000"), "idLog" : "4", "logAction" : "READ", "logUser" : "neto", "logTimestamp" : "2010-09-02 06:24:11", "logSection" : "Product" }

Isso funcionou porque nossa tabela de Logs é simples, uma tabela como a de produtos seria mais complexa:

 

Imagem Postada

 

Transformar essa modelagem relacional em:

 

Imagem Postada

 

Seria bem mais complexo devido a estrutura em árvore que será comum em qualquer banco relacional.

 

Precisamos fazer nosso Director poder decidir, em tempo de execução, qual o método de conversão deverá ser utilizado.

 

Alguém tem alguma sugestão para iterarmos os registros e decidir qual tipo de conversão deverá ser feito ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tudo depende da abse neh,s e tivermos bases simples com pouca herança fica simples.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.