Em um dos projetos que estamos trabalhando atualmente, estamos utilizando Rails e MongoDB juntamente com o Mongoid para fazer o relacionamento ODM (Object-Document-Mapper).
Nesse projeto temos alguns documentos onde armazenamos valores monetários; a primera coisa que fizemos foi mapear o campo para BigDecimal seguindo a documentação do Mongoid. Não vou entrar nos méritos dos motivos de se utilizar BigDecimal ao invés de Float pois não é esse o foco deste post. A questão é que não existe um tipo BigDecimal nativo no MongoDB, o Mongoid faz o trabalho sujo de converter esse valor pra você trabalhar em alto nivel, mas na base do MongoDB ele acaba sendo armazenado como String.
Não tinhamos problemas com isso maaaaaasssssssss, tudo na vida tem um porém, senão eu não estaria blogando sobre isso. Aconteceu que o cliente pediu para pesquisar por esses valores dentro de um range, por exemplo, de R$ 0,00 a R$ 1.000,00. Nenhum de nós percebeu problema nisso, e implementamos a busca, que aparentemente funcionou sem problemas. E digo aparentemente pois tinha funcionado em valores de 0 até 999.999, se eu usasse 800.000 a 1.000.000 por exemplo, mesmo existindo um documento com esse valor armazenado ele não listava.
O real problema era exatamente o fato de ele armazenar esses valores como String. Se usássemos inteiros ou floats a pesquisa funcionava, nossa intenção não era usar Float, pelos seus problemas naturais, e resolvemos usar Inteiros, armazenando-os com suas casas decimais, ou seja, o valor 1.530,99 seria armazenado como 153099. Confesso que é uma abordagem estranha, mas depois de alguns dias lutando com isso resolvemos seguir em frente e usar isso mesmo (se alguém souber algo por favor avise
), outro ponto a ser comentado, é que na aplicação não queriamos trabalhar com esse nivel, e resolvemos fazer o que o mongodb faz com o BigDecimal, mas ao invés de retornar um BigDecimal, resolvemos usar um objeto que representasse valores monetários, nesse caso o projeto Money.
Seguindo a documentação do Mongoid de como criar tipos customizados, criamos um tipo chamado MoneyField, o nome tem o Field no final para não conflitar com o nome da Gem e o codigo desse tipo ficou assim:
e no nosso documento fizemos somente um:
field :valor, type: Mongoid::MoneyField
o valor armazenado no mongodb é inteiro e o que tabalhamos na aplicação é um objeto to tipo Money.
Abraços.

