Berkenalan dengan Object [Relational | Document | Graph] Mapper

Ridwan Fajar 17 Mei 2015

Berkenalan dengan Object [Relational | Document | Graph] Mapper

Pendahuluan

 

Mungkin sudah tidak asing bagi Anda dengan istilah data definition language dalam operasi database relasional. Anda dapat membuat sebuah tabel yang memiliki kolom - kolom tertentu yang akan menyimpan data dari aplikasi Anda. Selain itu database relasional memiliki kemampuan untuk saling terhubung dengan tabel lain, sehingga Anda dapat membuat informasi yang atomik dan dapat bebas redundan jika rancangan database yang Anda rancang mampu menangani hal tersebut. Dalam membangun sebuah database relasional, ada yang menggunakan SQL mentah yang dieksekusi melalui konsol database relasional yang digunakan. Ada pula yang menggunakan software modeler yang memiliki kemampuan untuk menggambar terlebih dahulu entity relationship diagram (ERD), kemudian melakukan forward engineering yang secara otomatis akan menghasilkan tabel utama dan tabel relasional berdasarkan ERD yang dirancang.

[caption id="attachment_4243" align="aligncenter" width="600"]Merancang database relasional menggunakan CASE (Computer Aided Software Engineering) Merancang database relasional menggunakan CASE (Computer Aided Software Engineering)[/caption]

Namun ada juga beberapa developer yang memanfaatkan teknolog yang dikenal dengan object relational mapper (ORM), sebuah teknologi dimana kita dapat membuat database hanya dengan mendefinisikan class pada bahasa pemrograman tertentu, kemudian melakukan pembentukan database dari pendefinisian class tersebut. Kini, object mapper untuk database tidak hanya tersedia untuk database relasional saja. Database berbasis dokumen seperti MongoDB dan graf seperti Neo4j pun memiliki object mapper yang disebut dengan object document mapper (ODM) dan object graph mapper OGM. Tentu saja teknologi tersebut hadir untuk membantu developer dalam membangun database dengan mengurangi aktivitas manual yang sering dilakukan seperti melakukan pembuatan tabel atau koleksi.

Sebagai contoh untuk artikel ini, Python akan digunakan untuk memperlihatkan contoh penggunaan ORM, ODM, dan OGM. Penasaran? mari kita lanjutkan pembahasannya dibawah ini:

 

1. Object Relational Mapper (ORM)

 

Secara umum Object ORM merupakan sebuah tools yang akan membentuk tabel di sebuah database berdasarkan class yang didefinisikan oleh developer. ORM memiliki method yang dapat digunakan untuk berinteraksi dengan tabel tanpa harus melakukan SQL secara langsung. Dapat membentuk field relasional tanpa melakukan alter pada tabel yang dituju. Apabila Anda melakukan perpindahan mesin database pun dapat dengan mudah dilakukan tanpa perlu merombak banyak data definition language pada cara biasa.

ORM yang akan digunakan adalah SQLAlchemy. SQLAlchemy dapat membantu Anda dengan menggunakan method yang dimiliki SQLAlchemy atau menggunakan SQL mentah apabila proses yang akan dilakukan cukup kompleks. Sebagai contoh kita akan membuat sebuah database yang menyimpan berbagai jenis mesin database. Kita akan menggunakan SQLite untuk penyimpanannya:


engine = create_engine('sqlite:///codepolitan.db')
Base = declarative_base()
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()

Lalu kita buat sebuah class yang mewakili tabel Category dan DB_Engine seperti pada potongan class berikut:


class Category(Base):
    __tablename__ = 'category'

    id = Column (Integer, Sequence('category_id_seq'), primary_key=True)
    name = Column (String, nullable=False)

    def __repr__(self):
        return "Category - %s" % (self.name)

class DB_Engine(Base):
    __tablename__ = 'db_engine'

    id = Column (Integer, Sequence('db_engine_id_seq'), primary_key=True)
    name = Column (String, nullable=False)
    category_id = Column(Integer, ForeignKey('category.id'))
    category = relationship("Category", backref=backref('db_engine', order_by=id))

    def __repr__(self):
        return "DB_Engine - %s" % (self.name)

Pada souce code diatas kita menentukan kolom dengan sebuah variabel lokal di dalam class, nantinya field tersebut akan menjadi sebuah kolom di tabel pada mesin database yang Anda gunakan. Kemudian untuk relasi tabel, Anda cukup menunjuk salah satu field di class lain. Dalam melakukan proses pengisian tabel pun, SQL tidak digunakan secara langsung melainkan melalui method yang dimiliki sebuah ORM:


category_1 = Category(name='document-based database')
session.add(category_1)
category_2 = Category(name='relational database')
session.add(category_2)
session.commit()

session.add_all([
    DB_Engine(name="MySQL", category=category_2),
    DB_Engine(name="MariaDB", category=category_2),
    DB_Engine(name="PostgreSQL", category=category_2),
    DB_Engine(name="SQLite", category=category_2),
    DB_Engine(name="MongoDB", category=category_1),
    DB_Engine(name="CouchDB", category=category_1),
])
session.commit()

Dan terakhir, Anda dapat melalukan query hanya dengan memanggil chaining method tanpa harus membuat SQL yang cukup panjang untuk hal yang serupa:


list_db = session.query(DB_Engine).join(Category).all()
for db in list_db:
    print db.name , " is ", db.category.name

Beberapa contoh ORM lain yang sudah tersedia antara lain:

  • PHP: Propel, Doctrine, Readbean, Phalcon ORM, Symfoyny ORM
  • Python: SQLAlchemy, Django ORM
  • Java: Cayenne, Hibernate, ORMLite
  • Ruby: Rails Active Record, DataMapper
  • Node.js: Sequelize, Bookshelf, Node ORM, Waterline
  • Go: Gorm
  • Erlang: Hiberl
  • Perl: PerlORM, DBIx::Class
  • C#: NHibernate
  • C++: ODB, YB-ORM
 

[caption id="attachment_4245" align="aligncenter" width="600"]ORM berhasil dijalankan, data tersimpan ke SQLite3 dan isi tabel pun dapat diambil untuk ditampilkan ORM berhasil dijalankan, data tersimpan ke SQLite3 dan isi tabel pun dapat diambil untuk ditampilkan[/caption]

[caption id="attachment_4246" align="aligncenter" width="600"]Isi tabel Category dan DB_Engine yang dihasilkan secara otomatis oleh ORM Isi tabel Category dan DB_Engine yang dihasilkan secara otomatis oleh ORM[/caption]

 

2. Object Document Mapper (ODM)

 

Mirip dengan ORM hanya saja setiap class yang didefinisikan mewakili sebuah document yang otomatis akan tersimpan ke dalam sebuah collections. Anda tidak perlu memanggil terlebih dahulu memanggil nama koleksi kemudian menyimpan document kedalamnya, dengan ODM Anda cukup membuat sebuah instance dari class yang merupakan turunan dari Document, kemudian objek tersebut dapat melakukan penyimpanan data ke collection tertentu. Kali ini kita akan menggunakan ODM yang bernama MongoEngine.

Pertama kita harus terhubung ke server MongoDB yang akan kita gunakan:


connect('codepolitan') 

Kemudian kita harus mendefinisikan class yang merupakan inheritance dari Document milik MongoEngine. Kita dapat melewatkan validasi agar field name tidak terisi kosong. Selain itu kita dapat membuat field yang mereferensi sebuah collections dengan mudah:


class Category(Document):
    name = StringField(required=True)

class DB_Engine(Document):
    name = StringField(required=True)
    category = ReferenceField(Category)

Sekarang kita buat beberapa dokumen untuk collection Category dan DB_Engine. Hanya dengan melewatkan objek Category saat instansiasi objek DB_Engine, Anda dapat menyimpan sebuah nilai yang melakukan referensi dari tabel DB_Engine ke Category:


cat_1 = Category(name='document-based database')
cat_2 = Category(name='relational database')
cat_1.save()
cat_2.save()

db_1 = DB_Engine(name="MySQL", category=cat_2)
db_2 = DB_Engine(name="SQLite", category=cat_2)
db_3 = DB_Engine(name="PostgreSQL", category=cat_2)
db_4 = DB_Engine(name="MariaDB", category=cat_2)
db_5 = DB_Engine(name="MongoDB", category=cat_1)
db_6 = DB_Engine(name="CouchDB", category=cat_1)
db_1.save()
db_2.save()
db_3.save()
db_4.save()
db_5.save()
db_6.save()

Lalu untuk melakukan query, Anda hanya cukup memanggil objects dari suatu class tanpa melewati instansiasi. Kolom yang mereferensi ke Category pun sudah diambilkan secara otomatis tanpa harus mengambil lagi secara manual:


for item in DB_Engine.objects:
    print item.name, ' is ', item.category.name

Beberapa contoh ODM lain yang sudah tersedia antara lain:

  • PHP: Mandango, Doctrine MongoDB-ODM, Phalcon ODM
  • Python: MongoEngine, RethinkDB ODM, MongoAlchemy, Ming
  • Java: Mongolink
  • Ruby: Mongoid
  • Node.js: Mongoose
  • Go: Sleep
  • Erlang: Mongrel
  • Perl: Moose, Mandel
  • C#: MongoMapper.NET
  • C++: ODB
[caption id="attachment_4248" align="aligncenter" width="600"]ODM berhasil dijalankan, data tersimpan ke MongoDB dan isi collection pun dapat diambil untuk ditampilkan ODM berhasil dijalankan, data tersimpan ke MongoDB dan isi collection pun dapat diambil untuk ditampilkan[/caption]

[caption id="attachment_4249" align="aligncenter" width="600"]Isi collection Category dan DB_Engine yang dihasilkan secara otomatis oleh ODM Isi collection Category dan DB_Engine yang dihasilkan secara otomatis oleh ODM[/caption]

 

3. Object Graph Mapper (OGM)

 

OGM hampir mirip dengan ORM. Hanya saja OGM disediakan untuk graph database. Apabila class yang didefinisikan di ORM digunakan untuk membuat tabel, maka di graph database pendefinisian class dilakukan untuk membuat node. Sedangkan relasi pada class akan membentuk sebuah panah yang memiliki arah dari suatu node ke node yang dituju. Pada graf terdapat relasi dua arah, dimana hal tersebut berfungsi untuk melakukan query dalam proses traversal. Di contoh ini, OGM yang akan digunakan adalah Neomodel. Untuk contoh kasus, kita gunakan contoh kasus di pembahasan ORM. Kita mulai dengan membuat class yang mendefinisikan node:



class Category(StructuredNode):
    name = StringProperty(unique_index=True, required=True)

class Dbengine(StructuredNode):
    name = StringProperty(unique_index=True, required=True)
    category = RelationshipTo(Category, 'IS')

Kemudian kita membuat node untuk Category dan DB_Engine:

  
cat_1 = Category(name='relational database').save()
cat_2 = Category(name='document-based database').save()

db_1 = Dbengine(name='MySQL').save()
db_2 = Dbengine(name='PostgreSQL').save()
db_3 = Dbengine(name='SQLite').save()
db_4 = Dbengine(name='MariaDB').save()
db_5 = Dbengine(name='MongoDB').save()
db_6 = Dbengine(name='CouchDB').save()

Bedanya dengan database berbasis dokumen dan relasional, Anda harus menghubungkan setiap node jika ingin membentuk sebuah relasi atau keterkaitan data:


db_1.category.connect(cat_1)
db_2.category.connect(cat_1)
db_3.category.connect(cat_1)
db_4.category.connect(cat_1)
db_5.category.connect(cat_2)
db_6.category.connect(cat_2)

Anda pun tidak memerlukan cypher query language untuk mengambil sebuah node. Hanya saja untuk mendapatkan hasil query dengan banyak baris, Anda tetap memerlukan cypher query language untuk hasil yang diinginkan:


cat_1 = Category.index.get(name='relational database')
results = cat_1.cypher('MATCH (db: Dbengine)-[r:IS]->n return db.name, n.name')

for item in results[0]:
    print item[0], ' is ', item[1]

Seperti yang Anda lihat. Dengan menggunakan OGM, Anda akan beroperasi dengan Neo4j lebih mudah. Beberapa contoh OGM lain yang sudah tersedia antara lain:

  • Python: Neomodel, Mogwai
  • Ruby: neo4j
  • PHP: Neo4j PHP OGM
  • Java: Spring Data Neo4j, Object Graph Mapper
  • Node.js: Gremlin, Mogwai
  • Go: Titan
  • Perl: REST:Neo4p
 

[caption id="attachment_4250" align="aligncenter" width="600"]OGM berhasil dijalankan, data tersimpan ke Neo4j dan isi graf pun dapat diambil untuk ditampilkan OGM berhasil dijalankan, data tersimpan ke Neo4j dan isi graf pun dapat diambil untuk ditampilkan[/caption]

[caption id="attachment_4251" align="aligncenter" width="600"]Isi graf Category dan DB_Engine yang dihasilkan secara otomatis oleh OGM Isi graf Category dan DB_Engine yang dihasilkan secara otomatis oleh OGM[/caption]

Penutup

 

Pada umumnya object mapper untuk database dibangun diatas driver dasar, misal Neomodel dibangun diatas Py2Neo dan lainnya. Hanya saja dengan object mapper ini, Anda dapat menjaga konsistensi semisal saat pengisian data ke dalam suatu tabel, node, atau document. Beberapa fitur object mapper yang melakukan hal tersebut diantaranya adalah validasi pada setiap kolom, seperti pada contoh ORM diatas, kita melewatkan nilai required=True pada kolom nama karena field tersebut tidak boleh kosong.

Kemudian salah satu keunggulan ORM adalah mudahnya diintegrasikan dengan web framework, hal yang mungkin dilakukan adalah ketika Anda berpindah web framework kode program yang Anda gunakan tidak akan berubah banyak selama konfigurasi object mapper Anda masih sesuai.

Dengan menggunakan object mapper untuk database, Anda dapat dengan mudah membangun suatu database dan dapat mengurangi interaksi dengan database yang sudah umum dilakukan. Bahkan dengan menggunakan ORM/ODM/OGM, Anda dapat mengurangi beberapa kesulitan apabila menggunakan native database driver. Penggunaan tools diatas sangat bergantung kepada perencanaan oleh tim Anda, karena bisa jadi di antara teman tim Anda, ada yang lebih memfavoritkan cara konvensional dalam mengelola database dari aplikasi yang Anda kembangkan.

Untuk source code lengkap diatas, dapat Anda unduh disini. Semoga bermanfaat.

(rfs/wikipedia/nosql-database)