JsonDB - python實現的基於JSON格式的輕量級數據庫開源項目

JsonDB

jsonDB是一個基於JSON格式的內存數據庫.它具備如下特色:python

  • 輕量級. 無守護進程,無需任何額外的安裝和配置,你只須要import jsonDb便可使用,很是方便.
  • NOSQL. 相似於mongoDb的非關係型數據庫.
  • 內存數據庫. 全部數據基於內存進行操做和訪問,性能相對較高.目前版本的性能測試數據請 參考reference文檔.
  • 任意遷移. 數據庫能夠完整導出爲外部文件,而且能夠從外部文件導入.基於此,數據庫能夠 進行任意的遷移,而無需作任何修改.
  • 靈活的數據類型. 一個數據集合(collection)中的數據,並不須要相同的格式.好比如下幾種數據 能夠同時存在於一個collection中: {'key1':1},{'key2':'value','pic':'value'},{'key3':'value'}

JsonDB使用python語言實現,是一個github開源項目,遵循MIT的LICENCE,基本上能夠不受限制用於任何用途。git

該DB的接口大致模仿了mongoDB的風格,使用起來很是簡單和順手。github

概念說明:

  • db: 即數據庫. 建立一個jsonDb類的實例,便是建立了一個數據庫.能夠指定dbname和hash的長度.
  • collection: 數據集合(表). 一個collection能夠理解爲數據庫中的一個表. collection不須要 單首創建,當insert第一條數據,或者ensureKey時,系統會自動建立.
  • data: 數據. collection中的一條數據,或者是一個數據的list. data必須是dict字典類型,是一個 key-value鍵值對.

關鍵詞說明:

如下關鍵詞屬於系統保留,不能做爲任何字典dict的key名.數據庫

$lt 
$lte 
$gt 
$gte 
$ne 
$or 
$or[0-9] 
$jdb 
$jdb_collections 
$jdb_key 
$jdb_hash 
$jdb_coll 
$jdb_hashSize 
$jdb_md5

安裝

  1. 從源碼安裝,首先從github下載源碼,jsonDb源碼下載地址
python setup.py install
  1. pypi直接安裝,注意:本項目後續會上傳到pypi,目前僅支持源碼安裝.
pip install jsonDb

Filter條件過濾器

不少操做會使用到Filter條件過濾器.好比,刪除數據\更新數據\查詢數據等.經過過濾器,咱們能夠指定更新一組知足必定條件的數據. jsonDb提供了相對豐富和靈活的過濾器. 過濾器通常在方法的參數中使用filter來指定.json

filter是一個dict,它包括key,value,邏輯表達式,條件表達式 幾個部分.性能

filter={'邏輯表達式':{key:{'條件表達式':value}}}

邏輯表達式: 支持兩種邏輯測試

  1. 邏輯或: '$or' '$or1' '$or2'...,,若是存在多個邏輯或,須要使用$or[0-9],例如:
filter={'$or':{'key1':value1, 'key2':value2,...}, '$or1':{'key1':value1, 'key2':value2,...}, ...}
  1. 邏輯與: 沒有特殊的關鍵字,沒有使用邏輯或關鍵字的{}內的key之間就是邏輯與的關係,例如:
filter={'key1':value1, 'key2':value2,...}

條件表達式: 條件表達式是用來表示key和value之間的關係操作系統

  • 等於 {<key>:<value>}
  • 小於 {<key>:{$lt:<value>}}
  • 小於或等於 {<key>:{$lte:<value>}}
  • 大於 {<key>:{$gt:<value>}}
  • 大於或等於 {<key>:{$gte:<value>}}
  • 不等於 {<key>:{$ne:<value>}}

Filter支持任意嵌套,這樣使用起來會很是靈活.以下:debug

filter={'$or':{'key1':value1, '$or':{'key1':value1, '$or1':{'key1':value1, 'key2':value2,...},...},...}, 
        '$or1':{'key1':value1, 'key2':value2,...}, ...}

功能說明:

建立數據庫

實例化一個JSONDB類實例,即建立一個數據庫.咱們重載了__str__方法,因此能夠經過print直接查看數據庫的統計信息.調試

>>> from jsonDb.database import JSONDB
>>> myDb = JSONDB('USER_DB')
>>> print myDb

------ jdb statics ------
db_name: USER_DB
mem_collection: 0 bytes
mem_hash: 0 bytes
collection_num: 0
**** collection statics ****

刪除數據庫

jsonDB是內存數據庫,一個數據庫本質上就是一個類實例.因此數據庫隨類實例進行刪除和釋放.你能夠經過del方法刪除這個類實例, 固然也可讓python本身回收.

插入數據

插入一條數據,則對應的collection自動建立.能夠插入一條或多條數據,必須經過list格式組織.單條數據必須是dict格式.

>>> myDb.insert('COL_CUSTOMERS',[{'id':1, 'name':'Jeffery', 'sex':'male', 'age':18, 'birth':'1990-01-03'}])
True
>>> print myDb

------ jdb statics ------
db_name: USER_DB
mem_collection: 104 bytes
mem_hash: 0 bytes
collection_num: 1
**** collection statics **** 
 name: COL_CUSTOMERS
 data_num: 0
 key: []
 index: False
 data_mem: 104 bytes
 hash_mem: 0 bytes

>>>

能夠經過find()查看插入結果,爲了顯示格式更加便於閱讀,JSONDB提供了靜態格式化打印方法rprint():

>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS'),indent=4)
[
    {
        "name": "Jeffery", 
        "age": 18, 
        "id": 1, 
        "birth": "1990-01-03", 
        "sex": "male"
    }
]
>>>

也能夠同時插入多條數據

>>> dataList = [{'id':2, 'name':'Jack', 'sex':'male', 'age':29, 'birth':'1990-01-03'},
...             {'id':3, 'name':'Tom', 'age':18, 'birth':'1991-01-03'},
...             {'id':4, 'name':'Wang', 'sex':'male', 'age':40, 'job':'software engineer'}]
>>> myDb.insert('COL_CUSTOMERS',dataList)
True
>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS',filter={'id':{'$gte':2}}),indent=4)
[
    {
        "name": "Jack", 
        "age": 29, 
        "id": 2, 
        "birth": "1990-01-03", 
        "sex": "male"
    }, 
    {
        "age": 18, 
        "id": 3, 
        "birth": "1991-01-03", 
        "name": "Tom"
    }, 
    {
        "id": 4, 
        "job": "software engineer", 
        "age": 40, 
        "name": "Wang", 
        "sex": "male"
    }
]
>>>

上面使用了find()方法的條件查詢,只查詢了'id'大於等於2的數據.同時,每條data之間的格式不須要一致.

刪除數據

刪除一條指定的數據:

>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS',filter={'id':1}),indent=4)
[
    {
        "name": "Jeffery", 
        "age": 18, 
        "id": 1, 
        "birth": "1990-01-03", 
        "sex": "male"
    }
]
>>> myDb.delete('COL_CUSTOMERS',filter={'id':1})
True
>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS',filter={'id':1}),indent=4)
[]
>>>

一樣,咱們能夠經過filter過濾器來條件刪除多條數據,好比咱們要刪除全部'age'大於10而且小於30的記錄:

>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS'),indent=4)
[
    {
        "name": "Jack", 
        "age": 29, 
        "id": 2, 
        "birth": "1990-01-03", 
        "sex": "male"
    }, 
    {
        "age": 18, 
        "id": 3, 
        "birth": "1991-01-03", 
        "name": "Tom"
    }, 
    {
        "id": 4, 
        "job": "software engineer", 
        "age": 40, 
        "name": "Wang", 
        "sex": "male"
    }, 
    {
        "name": "Jeffery", 
        "age": 18, 
        "id": 1, 
        "birth": "1990-01-03", 
        "sex": "male"
    }
]
>>> myDb.delete('COL_CUSTOMERS',filter={'age':{'$gt':10,'$lt':30}})
True
>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS'),indent=4)
[
    {
        "id": 4, 
        "job": "software engineer", 
        "age": 40, 
        "name": "Wang", 
        "sex": "male"
    }
]
>>>

數據更新

>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS',filter={'name':'Wang'}),indent=4)
[
    {
        "id": 4, 
        "job": "software engineer", 
        "age": 40, 
        "name": "Wang", 
        "sex": "male"
    }
]
>>> myDb.update('COL_CUSTOMERS',set={'job':'doctor'},filter={'name':'Wang'})
True
>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS',filter={'name':'Wang'}),indent=4)
[
    {
        "id": 4, 
        "job": "doctor", 
        "age": 40, 
        "name": "Wang", 
        "sex": "male"
    }
]
>>>

數據查詢

數據查詢可使用Filter過濾器來實現豐富的查找功能.

>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS'),indent=4)
[
    {
        "name": "Jeffery", 
        "age": 18, 
        "id": 1, 
        "birth": "1990-01-03", 
        "sex": "male"
    }, 
    {
        "name": "Jack", 
        "age": 29, 
        "id": 2, 
        "birth": "1990-01-03", 
        "sex": "male"
    }, 
    {
        "age": 18, 
        "id": 3, 
        "birth": "1991-01-03", 
        "name": "Tom"
    }, 
    {
        "id": 4, 
        "job": "software engineer", 
        "age": 40, 
        "name": "Wang", 
        "sex": "male"
    }
]
>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS',filter={'$or':{'age':{'$gt':20},'id':{'$gte':3}}}),indent=4)
[
    {
        "name": "Jack", 
        "age": 29, 
        "id": 2, 
        "birth": "1990-01-03", 
        "sex": "male"
    }, 
    {
        "age": 18, 
        "id": 3, 
        "birth": "1991-01-03", 
        "name": "Tom"
    }, 
    {
        "id": 4, 
        "job": "software engineer", 
        "age": 40, 
        "name": "Wang", 
        "sex": "male"
    }
]

若是不指定collection,那麼將在整個數據庫中查找.目前暫不支持指定多個collection查找.

能夠經過limit參數來限制返回數據的條數,默認爲0,也就是返回全部.以下:

>>> JSONDB.rprint(myDb.find('COL_CUSTOMERS',filter={'$or':{'age':{'$gt':20},'id':{'$gte':3}}},limit=2),indent=4)
[
    {
        "name": "Jack", 
        "age": 29, 
        "id": 2, 
        "birth": "1990-01-03", 
        "sex": "male"
    }, 
    {
        "age": 18, 
        "id": 3, 
        "birth": "1991-01-03", 
        "name": "Tom"
    }
]

目前版本暫不支持排序和指定返回字段集,後續版本會陸續支持.

指定Key值

能夠經過ensureKey()給collection指定key值,這個key值是一個list,能夠是一個多元組key. 指定了key值的collection將會保證key值的惟一性,也就是說collection中的數據key值不會重複. 同時,指定了key值事後,將會爲該collection自動建立一個hash表,創建索引.在find()中, 若是filter是嚴格指定的key值,那麼將自動進行hash查找,查找效率比普通查找高不少.hash表 的大小在建立數據庫時能夠指定hashSize,默認是1000. 須要注意的是,咱們只能當collection裏面沒有數據時才能調用ensureKey(),一旦有插入數據後再指定Key值則失敗.

數據庫合併

經過merge()將一個數據庫合併到另一個數據庫裏面.合併中若是遇到數據衝突(好比key值衝突),則合併失敗.

>>> mergeDb = JSONDB('mergeDb')
>>> mergeDb.insert('COL1',[{'id':1,'name':'Wang'}])
True
>>> mergeToDb = JSONDB('mergeToDb')
>>> mergeToDb.insert('COL1',[{'id':2,'name':'LI'}])
True
>>> mergeToDb.insert('COL2',[{'idX':1,'nameX':'Lee'}])
True
>>> mergeDb.merge(mergeToDb)
True
>>> JSONDB.rprint(mergeDb.find(),indent=4)
[
    {
        "id": 1, 
        "name": "Wang"
    }, 
    {
        "id": 2, 
        "name": "LI"
    },
    {
        "idX": 1, 
        "nameX": "Lee"
    }
]
>>>

導出數據庫到外部文件

jsonDB是內存數據庫,爲了數據的持久存儲,咱們支持將內存數據庫導出到外部磁盤文件中.

>>> mergeDb.exportToFile()
True

默認將文件導出到./db/目錄下,db文件以數據庫的名字命名. 上例中將導出到./db/mergeDb.

導出的過程是比較耗時的,目前咱們不支持實時導出,須要使用者適配這部分功能.

從外部文件導入數據庫

支持從外部文件中導入數據到一個JSONDB類實例中.

>>> importDb = JSONDB('DB_IMPORT')
>>> importDb.importFromFile(fileName='mergeDb')
True

導入的數據庫文件,必須是經過exportToFile()導出生成的,不然導入操做可能會失敗. 爲了防止外部文件數據被篡改,咱們使用了MD5進行數據完整性校驗,因此不要修改導出的數據文件.

一些維測手段

調試打印開關

>>> myDb.debugSwitch(1)

格式化輸出

參數indent表示縮進的字符個數

>>> JSONDB.rprint(mergeDb.find(),indent=4)
[
    {
        "id": 1, 
        "name": "Wang"
    }, 
    {
        "idX": 1, 
        "nameX": "Lee"
    }
]

數據庫統計信息

使用print方法便可打印出數據庫的詳細統計信息.

>>> print myDb

------ jdb statics ------
db_name: USER_DB
mem_collection: 104 bytes
mem_hash: 0 bytes
collection_num: 1
**** collection statics **** 
 name: COL_CUSTOMERS
 data_num: 0
 key: []
 index: False
 data_mem: 104 bytes
 hash_mem: 0 bytes

>>>
  • db_name - 數據庫名
  • mem_collection - collection消耗的總內存
  • mem_hash - hash表消耗的總內存
  • collection_num - collection個數
  • collection statics - 分別顯示每一個collection的信息
    • name - collection名
    • data_num - data總條數
    • key - 指定的關鍵字列表
    • index - 是否創建了索引
    • data_mem - 數據佔用內存
    • hash_mem - hash表佔用內存

關鍵過程性能打點

方法perfDotStart()perfDotEnd()配對使用,提供對關鍵流程的耗時統計,毫秒級.

myDb.perfDotStart()
for i in range(1,1000):
    myDb.insert('COL_CUSTOMERS',[{'id':i, 'name':'Jeffery', 'sex':'male', 'age':18, 'birth':'1990-01-03'}])

myDb.find('COL_CUSTOMERS',filter={'id':500})
myDb.perfDotEnd()

輸出結果:

------ perf dot statics ------
[insert]spend time: 0.005295753479
[find]spend time: 0.014662027359

注意,這裏統計的是某個關鍵流程的總耗時.好比,期間進行了屢次insert()操做,那麼insert的耗時統計是全部這些的總和.

關於性能

jsonDb是基於內存存儲,因此總體性能足以知足一些小型的數據庫應用.

做者用來測試的PC性能:

mac air book
處理器  1.4 GHz Intel Core i5
內存  4 GB 1600 MHz DDR3
操做系統 OS X 10.9.5 (13F1603)

測試十萬條數據的插入\刪除\查詢操做:

from jsonDb.database import  JSONDB

myDb = JSONDB('USER_DB')

myDb.perfDotStart()
for i in range(0,100000):
    myDb.insert('COL_CUSTOMERS',[{'id':i, 'name':'Jeffery', 'sex':'male', 'age':18, 'birth':'1990-01-03'}])
myDb.perfDotEnd()

myDb.perfDotStart()
myDb.find('COL_CUSTOMERS',filter={'id':500})
myDb.perfDotEnd()

myDb.perfDotStart()
myDb.delete('COL_CUSTOMERS',filter={'id':10000})
myDb.perfDotEnd()

打點結果以下:

------ perf dot statics ------
[insert]spend time: 0.450565576553

------ perf dot statics ------
[find]spend time: 1.62476110458

------ perf dot statics ------
[find]spend time: 1.59516096115
[delete]spend time: 1.59673404694

指定了key值事後,會創建索引,因此會大大提升查找性能,可是插入性能會有必定降低.

from jsonDb.database import  JSONDB

myDb = JSONDB('USER_DB')

# 指定key值
myDb.ensureKey('COL_CUSTOMERS',['id'])

myDb.perfDotStart()
for i in range(0,100000):
    myDb.insert('COL_CUSTOMERS',[{'id':i, 'name':'Jeffery', 'sex':'male', 'age':18, 'birth':'1990-01-03'}])
myDb.perfDotEnd()

myDb.perfDotStart()
myDb.find('COL_CUSTOMERS',filter={'id':500})
myDb.perfDotEnd()

myDb.perfDotStart()
myDb.delete('COL_CUSTOMERS',filter={'id':10000})
myDb.perfDotEnd()

打點結果以下:

------ perf dot statics ------
[insert]spend time: 6.04253554344

------ perf dot statics ------
[find]spend time: 9.91821289062e-05

------ perf dot statics ------
[find]spend time: 6.50882720947e-05
[delete]spend time: 0.00128698348999

LICENCE

遵循 The MIT License (MIT),你能夠不受約束地使用該項目代碼和生成件.

反饋和交流

mail:hujiang001@gmail.com https://github.com/hujiang001/jsonDB

相關文章
相關標籤/搜索