Skip to main content

An interface between mongodb and basic python data structures

Project description

Mongolia

Mongolia is a wrapper of the pymongo library that lets you work with your mongo objects in a much more pythonic way.

It can be installed by pip:

pip install mongolia

The README that follows is a tutorial for the library. See the doc strings on the classes and functions themselves for the complete documentation.

For inquiries and customizations, email info[at]zagaran.com

Connecting to Your Database

Connecting to mongolia is simple:

from mongolia import connect_to_database, authenticate_connection
connect_to_database(host="example.com", port="12345")
authenticate_connection("username", "password")

# If your user is only authorized to access a single database, instead use this
authenticate_connection("username", "password", db="somedb")

Any further calls to mongolia will use this connection. If you are using mongolia with flask, this connection setup should go in app.py or in the global scope of a file imported by app.py. If you are using monglia with django, this connection setup should go in settings.py.

If you need to add a user to mongo, mongolia provides that functionality as well:

from mongolia import add_user
add_user("username", "password")

Note that in order to add the first user to a database, you need to be running mongo in unauthenticated mode. BE VERY CAREFUL WITH THIS. Make sure to shut down mongo and start in in authenticated mode when your done or else ANYONE IN THE WORLD WILL BE ABLE TO STEAL YOUR DATA.

DatabaseObject

By extending the python dictionary class, a DatabaseObject lets you interact easily with items in your databases. These are simply dictionaries with a few extra methods:

from mongolia import DatabaseObject, ID_KEY
path = "somedb.somecoll"

# Put a new item in the database
item = DatabaseObject.create({ID_KEY: "stuff", "key": "value"}, db=path)

# Modify the item and re-save it
item["key"] = "newval"
item.save()

# Get an item out of the database
item = DatabaseObject("stuff", db=path)
    # or just
item = DatabaseObject("stuff", path)

# Load an item by attribute rather than _id
item = DatabaseObject({"key": "newval"}, db=path)
    # or just
item = DatabaseObject(db=path, key="newval")

# Delete an item by
item.remove()

# Rename an item (changing it's ID_KEY)
item.rename("different_stuff")

It is worth noting that the ID_KEY of a dictionary (defined by Mongo as "_id") is always a required key of the DatabaseObject (so it will be an error if you try to create a DatabaseObject without either giving it an ID_KEY entry or setting random_id=True). When updating a DatabaseObject, changing the ID_KEY is also an error (as this is used by mongo to enforce uniqueness); instead, use the rename method.

DatabaseCollection

DatabaseCollection returns a collection as an explicit list of DatabaseObjects. When using this on larger collections, you can run out of memory; see "Dealing with Large Collections" below. Standard usage looks like this:

from mongolia import DatabaseCollection
path = "somedb.somecoll"

# Returns the entire collection
coll = DatabaseCollection(path)

# Returns the first ten elements of the collection (pages are 1-indexed for UI reasons)
coll = DatabaseCollection(path, page=1, page_size=10)

# Returns the number of elements in the collection
count = DatabaseCollection.count(path)

# Returns a specific filtering of the collection
coll = DatabaseCollection(path, query={"key": "newval"})
  # or just
coll = DatabaseCollection(path, key="newval")

# Returns a read-only copy of the collection
# (the items in the list will just be dicts, not DatabaseObjects, so you can't save them)
coll = DatabaseCollection(path, readonly=True)

# Returns a list of a specific field of elements in the collection
# (the following returns a list of _id's in the collection)
coll = DatabaseCollection(path, field="_id")

Subclasses and ORM

By subclassing DatabaseObject and DatabaseCollection, you can use mongolia as a full-fledged ORM (Object Relatiional Mapping; techinally this may be an OODBMS, but who cares).

In proper subclasses of DatabaseObject and DatabaseCollection, PATH arguments have already been specified and thus need not be included in intilization. Consequently, one could make a User subclass and do the following with it:

class User(DatabaseObject):
    PATH = "somedb.users"

class Users(DatabaseCollection):
    OBJTYPE = User

# load a user
user = User("user_id")

# load all users
users = Users()

# load all users with a particular setting
users = Users(status="active")

Also possibly present in a subclass is a DEFAULTS dictionary. This is a list of keys that can be assumed to be in the dictionary because when a DatabaseObject is saved or a value is pulled from it, any entry is completed from the DEFAULTS dictionary for that object. REQUIRED is a special key that indicates that the key in question is required for the object but there is no default. If a subclass of DatabaseObject is saved without an entry for a REQUIRED key, an error will be thrown. Note that ID_KEY is implicitly a REQUIRED key of all DatabaseObjects.

Values in the DEFAULTS dictionary may be either constants or functions; the differentiation is handled automatically by DatabaseObject. Best practice when modifying a function in the DEFAULTS dictionary is to go through the collection it is used on and re-save every item (thus applying the new function). Examples follow:

from mongolia import DatabaseObject, ID_KEY, REQUIRED, DatabaseCollection
from datetime import datetime

class TestObject(DatabaseObject):
    PATH = "test.test"
    DEFAULTS = {"description": REQUIRED, "metadata": None, "created": datetime.now}

# New objects must have required keys:
TestObject.create({ID_KEY: "test1"})
# raises mongolia.database_dict.MalformedObjectError:
#     "description" is a required key of TestObject

# When an object is saved, DEFAULTS are applied:
TestObject.create({ID_KEY: "test1", "description": "this is a test"})
# returns {'metadata': None, '_id': 'test1', 'description': 'this is a test',
#          'created': datetime.datetime(2012, 12, 11, 14, 14, 13, 754589)}


# Here is a decent way to handle a new function in DEFAULTS (if we didn't do this,
# then test_object["metadata"] would almost certainly have different values
# between loads of the object):
from random import random
class TestObject(DatabaseObject):
    PATH = "test.test"
    DEFAULTS = {"description": REQUIRED, "metadata": random,
                    "created": datetime.now}

class TestObjects(DatabaseCollection):  OBJTYPE = TestObject

# This is the line we have to run to update every object in the collection:
for test_object in TestObjects(): test_object.save()

You can have mongolia log warnings or even raise exceptions if you want stricter checking of DEFAULTS. This is very useful if you are using DEFAULTS to define schemas on your collections and want detect or prevent execution code that is not in line with your schema.

This is done with the following:

from mongolia import set_defaults_handling, AlertLevel

# This turns off alerts for access of keys not in DEFAULTS; this is the default behavior
set_defaults_handling(AlertLevel.none)

# This will cause a warning to be logged if a key is set on a DatabaseObject not in its DEFAULTS
set_defaults_handling(AlertLevel.warning)

# This will cause an exception to be raised if a key is set on a DatabaseObject not in its DEFAULTS
set_defaults_handling(AlertLevel.error)

Dealing with Large Collections

Mongolia gets good perfomance by loading entire collections into memory at query time. This is fine until your collections get large. In this case, to avoid running out of memory, you will want to use mongolia's memory-effient collection iterator. It fetches items in pages to limit memory use, but pages efficiently to keep the iteration linear instead of quadratic in runtime (a problem with pymongo's built-in paging).

# iterate over users
for user in Users.iterator():
    do_some_code(user)

# iterate over a subset of users
for user in Users.iterator(status="active"):
    do_some_code(user)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mongolia-0.7.0.tar.gz (22.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mongolia-0.7.0-py3-none-any.whl (26.5 kB view details)

Uploaded Python 3

File details

Details for the file mongolia-0.7.0.tar.gz.

File metadata

  • Download URL: mongolia-0.7.0.tar.gz
  • Upload date:
  • Size: 22.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for mongolia-0.7.0.tar.gz
Algorithm Hash digest
SHA256 cc9a331e43890a682d6f2e784106abd883419f25ae927538b6f36911f8b137b5
MD5 30677456fe71503c36661bcedd8b2043
BLAKE2b-256 67afe641c6bc489f307d15b34e93fa235cce2f57f3a4e95b11536a249d2cf0f6

See more details on using hashes here.

File details

Details for the file mongolia-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: mongolia-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 26.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for mongolia-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 57badedd13c85544daea8058659e7518d6bb8cb63f3b69c00b3842bd71328121
MD5 c85e5c75617907ff21b415b71c0e7ef7
BLAKE2b-256 810d61cf1ddbef4c5d3ad745bc136de4c6139f9759ce229acf0780a908f56721

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page