mongodol.base#
Base mongoDB data object layers
Functions
|
The parts of |
Classes
|
A |
|
A |
|
Base class wrapping a mongo collection with a fixed |
|
A base class to read from a mongo collection, or subset thereof, with the Mapping (i.e. dict-like) interface. |
|
base class to read from and write to a mongo collection, or subset thereof, with the MutableMapping interface. |
|
A base class to read from a mongo collection, or subset thereof, with the Mapping (i.e. dict-like) interface. |
|
Base Mongo Db Reader. |
- class mongodol.base.MongoBaseStore(store=<class 'dict'>)[source]#
Bases:
StoreA
Storethat forwards the mongo bulk-read protocol through its transforms.Historically this was the only way to get
values()/items()to honour a wrapper’s transforms – hencemongodol.trans.wrap_kvs, which uses it as the wrapper class. It is no longer needed for that:mongodol.viewsresolves the bulk path through any wrapper chain, so plaindol.wrap_kvsnow works too. It is kept because it also forwards the write-side bulk methods (append/extend), and because code may calliter_values()/contains_value()directly.- contains_item(item)[source]#
Forward
contains_itemto the wrapped store, transforming key and value first.
- iter_items()[source]#
Bulk-read all
(key, value)pairs, transforming each with_key_of_id/_obj_of_data.
- persist_data(data, key=None)[source]#
Write
dataunderkey, through this wrapper’s own__setitem__.Unlike the leaf’s
persist_data(a thin{ID: data[ID]} -> datashortcut), this routes throughself[key] = data, so it applies_id_of_key/_data_of_objinstead of bypassing them (see i2mint/mongodol#11).keydefaults to being inferred fromdata[ID], for backward compatibility with the previous leaf-bound behaviour – but that inference itself bypasses the key codec, so passkeyexplicitly wherever the caller already knows it.
- class mongodol.base.MongoClientReader(host=None, port=None, document_class=<class 'dict'>, tz_aware=None, connect=None, type_registry=None, **kwargs)[source]#
Bases:
KvReaderA
Mappingview of a mongo client. Keys are database names, values areMongoDbReaderinstances for the corresponding database.Takes the same arguments as
pymongo.MongoClient.>>> from mongodol.base import MongoClientReader, MongoDbReader >>> from mongodol.util import mk_dflt_mgc >>> _ = mk_dflt_mgc().insert_one({'x': 1}) # ensure the default db/collection exist >>> client_reader = MongoClientReader() >>> 'mongodol' in client_reader True >>> db_reader = client_reader['mongodol'] >>> isinstance(db_reader, MongoDbReader) True
- class mongodol.base.MongoCollectionCollection(mgc=None, filter=None, iter_projection=None, **mgc_find_kwargs)[source]#
Bases:
CollectionBase class wrapping a mongo collection with a fixed
filteranditer_projection.- property mgc_repr#
A short
<database/collection>string identifying the wrapped mongo collection.
- class mongodol.base.MongoCollectionFieldsReader(mgc=None, filter=None, key_fields=('_id',), val_fields=None)[source]#
Bases:
MongoCollectionReaderA base class to read from a mongo collection, or subset thereof, with the Mapping (i.e. dict-like) interface.
An “easier” interface for the common case where we just want to specify fixed fields for keys and vals.
- class mongodol.base.MongoCollectionPersister(mgc=None, filter=None, on_write_filter=None, iter_projection=('_id',), getitem_projection=None, *, allow_operators_in_write_keys=None, **mgc_find_kwargs)[source]#
Bases:
MongoCollectionReaderbase class to read from and write to a mongo collection, or subset thereof, with the MutableMapping interface.
>>> from mongodol.util import mk_dflt_mgc >>> mongo_collection_obj = mk_dflt_mgc() >>> s = MongoCollectionPersister(mongo_collection_obj, getitem_projection={'_id': False}) >>> for k in s: # deleting all docs in default collection ... del s[k] >>> k = {'_id': 'foo'} >>> v = {'val': 'bar'} >>> k in s # see that key is not in store (and testing __contains__) False >>> len(s) 0 >>> s[k] = v >>> len(s) 1 >>> list(s) [{'_id': 'foo'}]
Since this is a base mongo store, the values are cursors, so to get an actual value, you need to fetch the first doc
>>> next(s[k]) {'val': 'bar'} >>> next(s.get(k)) {'val': 'bar'}
Remember (see
MongoCollectionReaderdocs) thats.getwill never reach its default since the reader will always return a cursor (possibly empty). So in the following case, we should get an empty cursor (not a default value)>>> list(s.get({'not': 'a key'}, {'default': 'val'})) # testing s.get with default []
>>> list(s.values()) [{'val': 'bar'}] >>> k in s # testing __contains__ again True >>> k in s.keys() # test the contains capability of s.keys() (a MongoKeysView instance) True >>> del s[k] >>> len(s) 0
>>> # Making a persister whose keys are 2-dimensional and values are 3-dimensional >>> from mongodol.util import normalize_projection >>> s = MongoCollectionPersister(mongo_collection_obj, ... iter_projection={'first': True, 'last': True, '_id': False}, ... getitem_projection=normalize_projection(('yob', 'proj', 'bdfl'))) >>> for _id in s: # deleting all docs in tmp ... del s[_id] >>> # writing two items >>> s[{'first': 'Guido', 'last': 'van Rossum'}] = {'yob': 1956, 'proj': 'python', 'bdfl': False} >>> s[{'first': 'Vitalik', 'last': 'Buterin'}] = {'yob': 1994, 'proj': 'ethereum', 'bdfl': True} >>> # Seeing that those two items are there >>> for key, val in s.items(): ... print(f"{key} --> {val}") {'first': 'Guido', 'last': 'van Rossum'} --> {'yob': 1956, 'proj': 'python', 'bdfl': False} {'first': 'Vitalik', 'last': 'Buterin'} --> {'yob': 1994, 'proj': 'ethereum', 'bdfl': True}
Writes stay inside the store’s scope: a key or value that contradicts a field of the write filter (
on_write_filter, elsefilter) raisesValueError. Fields scoped with operators other than$eq/$in(such as$ne,$gt) are NOT checked and such writes are let through: give those stores anon_write_filterwith plain values. Keys used to replace or delete docs may not contain$-operators or regexes (passallow_operators_in_write_keys=True, or set it as a class attribute, to allow them), and those queries are confined byfilterandon_write_filter. Reads (s[k],k in s) still accept query keys, always withinfilter.- allow_operators_in_write_keys = False#
Whether keys given to write/delete operations may contain
$-operators.
- append(v)[source]#
Insert a single doc
v, merged withon_write_filterif set, else this store’s filter.
- class mongodol.base.MongoCollectionReader(mgc=None, filter=None, iter_projection=('_id',), getitem_projection=None, **mgc_find_kwargs)[source]#
Bases:
MongoCollectionCollection,KvReaderA base class to read from a mongo collection, or subset thereof, with the Mapping (i.e. dict-like) interface.
Some examples below. For examples using actual data (with setup and tear down) see the tests/ folder.
>>> from pymongo import MongoClient >>> s = MongoCollectionReader(MongoClient()['mongodol']['mongodol_test']) >>> list_of_keys = list(s) >>> fake_key = {'_id': 'this key does not exist'} >>> fake_key in s False
It’s important to note that
s[k](for any base MongoCollectionReader instances) returns a Cursor, and will always return a Cursor, no matter what keykyou ask for – as long as the key is a valid mapping (dict usually). This cursor is a (pymongo) object that is used to iterate over the results of theklookup. It may yield no results what-so-ever, or one, or many.>>> v = s[fake_key] >>> type(v).__name__ 'Cursor' >>> len(list(v)) # but the cursor yields no results 0
Indeed,
MongoCollectionReaderis really meant to provide a low level key-value interface to a mongo collection that is really meant to be wrapped in order to produce the actual key-value interfaces one needs. You shouldn’t think of it’s instances as a normal dict where any request for the value under a key, for a key that doesn’t exist, will result in aKeyError. Note that this means thats.get(k, default)will never result in the default being returned, since there are no missing keys here; only empty results (cursors that don’t yield anything).>>> v = s.get(fake_key, {'the': 'default'}) >>> assert v != {'the': 'default'}
s.keys(),s.values(), ands.items()arecollections.abc.MappingViewsinstances (specialized for mongo – seemongodol.views: they fetch the whole collection in a single query, and keep doing so, correctly, when the store is wrapped bydol).>>> assert type(s.keys()) == s.KeysView >>> assert type(s.values()) == s.ValuesView >>> assert type(s.items()) == s.ItemsView
Recall that
collections.abc.MappingViewshave many set-like functionalities:>>> fake_key in s.keys() False >>> a_list_of_fake_keys = [{'_id': 'fake_key'}, {'_id': 'yet_another'}] >>> s.keys().isdisjoint(a_list_of_fake_keys) True >>> s.keys() & a_list_of_fake_keys set() >>> fake_value = {'data': "this does not exist"} >>> fake_value in s.values() False >>> fake_item = (fake_key, fake_value) >>> fake_item in s.items() False
Note though that since keys and values are both dictionaries in mongo, some of these set-like functionalities might not work (complaints such as
TypeError: unhashable type: 'dict'), such as:>>> s.keys() | a_list_of_fake_keys Traceback (most recent call last): ... TypeError: unhashable type: 'dict'
But you can take care of that in higher level wrappers that have hashable keys and/or values.
- ItemsView#
alias of
MongoItemsView
- ValuesView#
Views that resolve the bulk-read fast path through any
dolwrapper chain, rather than through blind attribute delegation. Seemongodol.views.alias of
MongoValuesView
- aggregate(pipeline, **kwargs)[source]#
Run a mongo aggregation
pipeline, prefixed with a$matchon this store’s filter.
- contains_value(v)[source]#
Bulk-read counterpart of
__contains__for values: is there a doc matchingv?
- distinct(key, filter=None, **kwargs)[source]#
The distinct values of
keyacross docs matchingfilter(merged with this store’s own filter).
- classmethod from_params(db_name='mongodol', collection_name='test', mongo_client=None, filter=None, iter_projection=('_id',), getitem_projection=None, **mgc_find_kwargs)[source]#
Make an instance from db/collection names and connection params, instead of a live mongo collection object.
- iter_items()[source]#
Bulk-read all
(key, value)pairs in a singlefindquery, splitting each doc into its key fields and the rest.
- iter_values()[source]#
Bulk-read all values in a single
findquery (see the module’s bulk-read protocol).
- property key_fields#
The field names (from
iter_projection) that make up a key.
- unique(key, filter=None, **kwargs)#
The distinct values of
keyacross docs matchingfilter(merged with this store’s own filter).
- property val_fields#
The field names (from
getitem_projection) that make up a value, or None if unset.
- class mongodol.base.MongoDbReader(db_name='mongodol', mk_collection_store=<class 'mongodol.base.MongoCollectionReader'>, mongo_client=None, **mongo_client_kwargs)[source]#
Bases:
KvReaderBase Mongo Db Reader. Keys are collection names and values are collection store instances.
- Parameters:
db_name – Name of db
mk_collection_store – Function that is called on a key (collection name) to make the collection store instance. Use mk_collection_store to define what kind of collection stores you want to make. Will be called with only one unnamed argument; the collection name. Use custom classes here, and/or partials (curried functions) thereof, to fix any parameters you want to fix.
mongo_client – MongoClient instance, kwargs to make it (
MongoClient(**kwargs)), or callable to make itmongo_client_kwargs –
**kwargsto make a MongoClient, that is used if mongo_client is callable
>>> from mongodol.base import MongoDbReader >>> from mongodol.util import mk_dflt_mgc >>> _ = mk_dflt_mgc().insert_one({'x': 1}) # ensure the default db/collection exist >>> db_reader = MongoDbReader() >>> 'mongodol_test' in db_reader True
- mongodol.base.operator_field_names(obj)[source]#
The parts of
objthat make it act as a query rather than an exact match.That is:
$-prefixed field names and regular-expression values, found at any depth (in mappings and lists). Regexes are reported by theirrepr.- Return type:
>>> operator_field_names({'a': 1, 'b': {'c': [{'$gt': 2}]}}) ['$gt'] >>> operator_field_names({'a': re.compile('x')}) ["re.compile('x')"] >>> operator_field_names({'a': 1}) []