{ "info": { "author": "Johan Egneblad", "author_email": "johan@DELETEMEegneblad.se", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": ".. image:: https://travis-ci.org/eblade/jsonobject.svg?branch=master\n :target: https://travis-ci.org/eblade/jsondb\n\n\njsondb\n======\n\nJSON Key-Value store in pure Python 3\n\nIntroduction\n------------\n\nJSONDB is a library for Python 3 that provides the ability to run a very\nsimplified CouchDB-like document database, a.k.a. a Key-Value store. The\nfeatures include:\n\n- Hard disk storage of documents\n- In-memory storage of indexes\n- Map and reduce functions specified in Python directly\n- Any number of views per database\n- Views can be accessed with or without reducing them\n- Thread-safe (with locks per database)\n\n\nInstallation\n------------\n\nYou can `pip` (python 3) install this Github repository or a tag, like this:\n\n $pip install https://github.com/eblade/jsondb/archive/0.2.tar.gz\n\n\nThis will also install `blist` which is used to get the views faster.\n\n\nExamples\n--------\n\nTo create a new database (a table if you think in relation database terms):\n\n\n.. code:: python\n\n >>> from lindh.jsondb import Database\n >>> db = Database('/tmp/cars')\n >>> db.clear() # for doctest purposes\n\n\nThis will create a folder `/tmp/cars` which will be used to store the\ndocuments (json files) and an ID counter.\n\nTo populated the database with some content you can use ``db.save(...)``.\nThese documents will be given a unique ``id`` automatically. If you just\nwant to retrieve them using indices, this is not a problem, but if you\nwant control over the identifiers, you can do like this instead:\n\n\n.. code:: python\n\n >>> db[0] = {'brand': 'Volvo', 'model': 'S40', 'wheels': 6}\n >>> db[1] = {'brand': 'Mercedes', 'model': 'C', 'wheels': 8}\n >>> db[2] = {'brand': 'Volvo', 'model': 'V70', 'wheels': 4}\n >>> db[3] = {'brand': 'Honda', 'model': 'CB500F', 'wheels': 2}\n\n\nThis enables you to retrieve them back in the expected pythonic way.\n\nThe documents are stored synchronously, so your app may be restarted\nwithout data loss.\n\nLet's look at an interactive session to find out what the document\nlooks like when it comes back:\n\n\n.. code-block:: python\n\n >>> db[0] == {'wheels': 6, '_id': 0, '_rev': 0, 'brand': 'Volvo', 'model': 'S40'}\n True\n\n\nAs you can see, the structure closely mimic that of CouchDB, with the\n``_id`` and ``_rev`` fields. The ``_rev`` field is important to keep intact\nas updated requires it to be the latest (otherwise a ``lindh.jsondb.Conflict``\nis raised). To update, it's quite easy to use save (but index-based\nsetting also works):\n\n\n.. code-block:: python\n\n >>> db.save({'wheels': 6, '_id': 0, '_rev': 0, 'brand': 'Volvo', 'model': 'S40', 'color': 'white'}) == \\\n ... {'wheels': 6, '_id': 0, '_rev': 1, 'brand': 'Volvo', 'model': 'S40', 'color': 'white'}\n True\n\n\nThe ``_rev`` should change here, usually pop one number up (whereas\nCouchDB would return random hashes for each revision).\n\nTo delete a document you can simple use ``del db[key]`` or\n``db.delete(key)``.\n\n\nViews\n~~~~~\n\nWhat fun is a Key-Value store with no indexing? Not much!\n\n.. code:: python\n\n >>> db.define('by_wheels', lambda o: (o['wheels'], ' '.join([o['brand'], o['model']])))\n >>> list(db.view('by_wheels'))[0] == \\\n ... {'id': 3, 'key': 2, 'value': 'Honda CB500F'}\n True\n\n\nSo we defined a view called ``by_wheels`` where the number of wheels\nis used as key and a concatenation of brand and model is used as\nvalue. The view is always sorted so I know that the motorcycle will\ncome out first. The rest of the order is somewhat arbitrary since\na binary search tree is used to hold the index in memory.\n\nNote that the index is available as soon as it is created. This is\nbecause the operation of defining an index is asynchronous. It does\nnot matter if the view is defined before or after the documents are\ncreated, as the documents will be placed in the index ad hoc. They\nwill also be deleted that way. This means, for performance:\n\n- Adding a document is O(log n)\n- Finding a document is O(log n)\n- Deleting a document is O(log n)\n\nSo this scales quite well as long as the index fits in memory (the\nactual documents do not need to fit in memory, however). By the nature\nof being a binary search tree, it is constantly sorted by key.\n\nNow, this takes us to the sorting. To further mimic CouchDB, keys need\nto be sortable beyond the core functionality of python. Anything needs\nto be comparable with anything basically. Also, we need something to\nbe smaller and bigger than everything else, respectively. These are\n``None`` and ``any``.\n\nLets revisit the ``by_wheels`` view, and take everything with equal to\nor more than 6 wheels (I know this is not accurate data).\n\n.. code:: python\n\n >>> list(db.view('by_wheels', startkey=6, endkey=any)) == \\\n ... [{'id': 0, 'key': 6, 'value': 'Volvo S40'},{'id': 1, 'key': 8, 'value': 'Mercedes C'}]\n True\n\nThe reason to use ``list()`` here is because I'm always given a\ngenerator back.\n\n\nMore on Views\n~~~~~~~~~~~~~\n\nA number of keyword arguments can be passed to the ``view(...)`` method:\n\n- ``key`` specifies a single key (which can give 0 to many values)\n- ``startkey`` specifies an inclusive starting point. Can be a tuple.\n- ``endkey`` specifies and inclusive ending point. Can be a tuple.\n- ``include_docs``, if ``True``, the document that rendered this index\n post is included under ``doc``.\n- ``group``, if ``True`` and a ``reduce`` function is specified as a\n third argument to the ``define`` method, the result will be the\n reduced data rather than the mapped.\n- ``no_reduce``, if there is a reduce function, but you don't want to\n use it this time, set this to ``True`` and leave ``group`` as\n ``False``.\n- ``skip``, an integer offset (defaults to ``0``)\n- ``limit``, an integer page size (set to ``None`` for no limit)\n\n\nFor more information about reduce functions please see the CouchDB\ndocumentation. The big differences are:\n\n- Group levels are not supported. Grouping is always done on the deepest\n level (meaning all elements in a tuple key).\n- Re-reduce is never done. But. The reduce function nevertheless expects\n ``f(keys, values, rereduce)``. This potentially leads to scaling\n issues but I have not run into them yet.\n\n\nFurther Reading\n---------------\n\n- The lib is developed mainly for the Images6 project, found at\n https://github.com/eblade/images6. This means it's full of usage\n examples. Look into ``images6/system.py`` for instance to see how\n the views are set up.\n\n- Also the lib works quite well together with its sister, ``lindh-jsonobject``\n which is a Django-inspired serialization/deserialization lib for\n complex python objects and json. It can be found here:\n https://github.com/eblade/jsonobject.\n\n\nAuthor\n------\n\n``lindh.jsondb`` is written and maintained by Johan Egneblad .\n\n\n", "description_content_type": "text/x-rst", "docs_url": null, "download_url": "https://github.com/eblade/jsondb/archive/v0.3.0.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/eblade/jsondb", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "lindh-jsondb", "package_url": "https://pypi.org/project/lindh-jsondb/", "platform": "", "project_url": "https://pypi.org/project/lindh-jsondb/", "project_urls": { "Download": "https://github.com/eblade/jsondb/archive/v0.3.0.tar.gz", "Homepage": "https://github.com/eblade/jsondb" }, "release_url": "https://pypi.org/project/lindh-jsondb/0.3.0/", "requires_dist": [ "blist (>=1.3.6)" ], "requires_python": "", "summary": "JSON based document database", "version": "0.3.0" }, "last_serial": 5600571, "releases": { "0.3.0": [ { "comment_text": "", "digests": { "md5": "83fb3f0beeba3f922b025504082713a0", "sha256": "f18a5d8e4e5700236fa5dd0e963065376f394cf13feb200f6db62136ac23597d" }, "downloads": -1, "filename": "lindh_jsondb-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "83fb3f0beeba3f922b025504082713a0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8670, "upload_time": "2019-07-29T17:06:48", "url": "https://files.pythonhosted.org/packages/e6/82/2872935c1890017b231fdd9b51995caf77ce7d4ba85830567adfb3dca377/lindh_jsondb-0.3.0-py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "83fb3f0beeba3f922b025504082713a0", "sha256": "f18a5d8e4e5700236fa5dd0e963065376f394cf13feb200f6db62136ac23597d" }, "downloads": -1, "filename": "lindh_jsondb-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "83fb3f0beeba3f922b025504082713a0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8670, "upload_time": "2019-07-29T17:06:48", "url": "https://files.pythonhosted.org/packages/e6/82/2872935c1890017b231fdd9b51995caf77ce7d4ba85830567adfb3dca377/lindh_jsondb-0.3.0-py3-none-any.whl" } ] }