def count(cls, filter=None, **kwargs): """Return a count of documents matching the filter""" from mongoframes.queries import Condition, Group, to_refs if isinstance(filter, (Condition, Group)): filter = filter.to_dict() filter = to_refs(filter) if filter: return cls.get_collection().count_documents( to_refs(filter), **kwargs) else: return cls.get_collection().estimated_document_count(**kwargs)
def many(cls, filter=None, **kwargs): """Return a list of documents matching the filter""" from mongoframes.queries import Condition, Group, to_refs # Flatten the projection kwargs['projection'], references, subs = \ cls._flatten_projection( kwargs.get('projection', cls._default_projection) ) # Find the documents if isinstance(filter, (Condition, Group)): filter = filter.to_dict() documents = list(cls.get_collection().find(to_refs(filter), **kwargs)) # Dereference the documents (if required) if references: cls._dereference(documents, references) # Add sub-frames to the documents (if required) if subs: cls._apply_sub_frames(documents, subs) return [cls(d) for d in documents]
def insert_many(cls, documents): """Insert a list of documents""" from mongoframes.queries import to_refs # Ensure all documents have been converted to frames frames = cls._ensure_frames(documents) assert len([f for f in frames if '_id' in f._document]) == 0, \ "Can't insert documents with `_id`s" # Send insert signal signal('insert').send(cls, frames=frames) # Prepare the documents to be inserted documents = [to_refs(f._document) for f in frames] # Bulk insert ids = cls.get_collection().insert_many(documents).inserted_ids # Apply the Ids to the frames for i, id in enumerate(ids): frames[i]._id = id # Send inserted signal signal('inserted').send(cls, frames=frames) return frames
def update(self, *fields): """ Update this document. Optionally a specific list of fields to update can be specified. """ from mongoframes.queries import to_refs assert '_id' in self._document, "Can't update documents without `_id`" # Send update signal signal('update').send(self.__class__, frames=[self]) # Check for selective updates if len(fields) > 0: document = {} for field in fields: document[field] = self._path_to_value(field, self._document) else: document = self._document # Prepare the document to be updated document = to_refs(document) document.pop('_id', None) # Update the document self.get_collection().update_one({'_id': self._id}, {'$set': document}) # Send updated signal signal('updated').send(self.__class__, frames=[self])
def one(cls, filter=None, **kwargs): """Return the first document matching the filter""" from mongoframes.queries import Condition, Group, to_refs # Flatten the projection kwargs['projection'], references, subs = \ cls._flatten_projection( kwargs.get('projection', cls._default_projection) ) # Find the document if isinstance(filter, (Condition, Group)): filter = filter.to_dict() document = cls.get_collection().find_one(to_refs(filter), **kwargs) # Make sure we found a document if not document: return # Dereference the document (if required) if references: cls._dereference([document], references) # Add sub-frames to the document (if required) if subs: cls._apply_sub_frames([document], subs) return cls(document)
def count(cls, filter=None, **kwargs): """Return a count of documents matching the filter""" from mongoframes.queries import Condition, Group, to_refs if isinstance(filter, (Condition, Group)): filter = filter.to_dict() return cls.get_collection().count(to_refs(filter), **kwargs)
def nullify(cls, ref_cls, field, frames): """Nullify a reference field (does not emit signals)""" from mongoframes.queries import to_refs ids = [to_refs(f[field]) for f in frames if f.get(field)] ref_cls.get_collection().update_many( {field: {'$in': ids}}, {'$set': {field: None}} )
def pull(cls, ref_cls, field, frames): """Pull references from a list field (does not emit signals)""" from mongoframes.queries import to_refs ids = [to_refs(f[field]) for f in frames if f.get(field)] ref_cls.get_collection().update_many( {field: {'$in': ids}}, {'$pull': {field: {'$in': ids}}} )
def update_many(cls, documents, *fields): """ Update multiple documents. Optionally a specific list of fields to update can be specified. """ from mongoframes.queries import to_refs # Ensure all documents have been converted to frames frames = cls._ensure_frames(documents) all_count = len(documents) assert len([f for f in frames if '_id' in f._document]) == all_count, \ "Can't update documents without `_id`s" # Send update signal signal('update').send(cls, frames=frames) # Prepare the documents to be updated # Check for selective updates if len(fields) > 0: documents = [] for frame in frames: document = {'_id': frame._id} for field in fields: document[field] = cls._path_to_value( field, frame._document ) documents.append(to_refs(document)) else: documents = [to_refs(f._document) for f in frames] # Update the documents for document in documents: _id = document.pop('_id') cls.get_collection().update( {'_id': _id}, {'$set': document}) # Send updated signal signal('updated').send(cls.__class__, frames=frames)
def update_many(cls, documents, *fields): """ Update multiple documents. Optionally a specific list of fields to update can be specified. """ from mongoframes.queries import to_refs # Ensure all documents have been converted to frames frames = cls._ensure_frames(documents) all_count = len(documents) assert len([f for f in frames if '_id' in f._document]) == all_count, \ "Can't update documents without `_id`s" # Send update signal signal('update').send(cls, frames=frames) # Prepare the documents to be updated # Check for selective updates if len(fields) > 0: documents = [] for frame in frames: document = {'_id': frame._id} for field in fields: document[field] = cls._path_to_value( field, frame._document) documents.append(to_refs(document)) else: documents = [to_refs(f._document) for f in frames] # Update the documents requests = [] for document in documents: _id = document.pop('_id') requests.append(UpdateOne({'_id': _id}, {'$set': document})) cls.get_collection().bulk_write(requests) # Send updated signal signal('updated').send(cls, frames=frames)
def ids(cls, filter=None, **kwargs): """Return a list of Ids for documents matching the filter""" from mongoframes.queries import Condition, Group, to_refs # Find the documents if isinstance(filter, (Condition, Group)): filter = filter.to_dict() documents = cls.get_collection().find(to_refs(filter), projection={'_id': True}, **kwargs) return [d['_id'] for d in list(documents)]
def ids(cls, filter=None, **kwargs): """Return a list of Ids for documents matching the filter""" from mongoframes.queries import Condition, Group, to_refs # Find the documents if isinstance(filter, (Condition, Group)): filter = filter.to_dict() documents = cls.get_collection().find( to_refs(filter), projection={'_id': True}, **kwargs ) return [d['_id'] for d in list(documents)]
def insert(self): """Insert this document""" from mongoframes.queries import to_refs # Send insert signal signal('insert').send(self.__class__, frames=[self]) # Prepare the document to be inserted document = to_refs(self._document) # Insert the document and update the Id self._id = self.get_collection().insert_one(document).inserted_id # Send inserted signal signal('inserted').send(self.__class__, frames=[self])
def inc(cls, account, date, stats): """Increment the given stats (`{stat1: amount1, stat2: amount2}`)""" incs = {} for stat, amount in stats.items(): for key in cls.get_inc_keys(date, stat): incs[f'values.{key}'] = amount for scope in ['all', to_refs(account)]: cls.get_collection().update((Q.scope == scope).to_dict(), { '$set': { 'scope': scope }, '$inc': incs }, w=0, upsert=True)
def __init__(self, frame_cls, filter=None, per_page=20, orphans=0, **filter_args): # The frame class results are being paginated for self._frame_cls = frame_cls # The filter applied when selecting results from the database (we # flattern the filter at this point which effectively deep copies. if isinstance(filter, (Condition, Group)): self._filter = filter.to_dict() else: self._filter = to_refs(filter) # Any additional filter arguments applied when selecting results such as # sort and projection, self._filter_args = filter_args # The number of results that will be displayed per page self._per_page = per_page # If a value is specified for orphans then the last page will be able to # hold the additional results (up to the value of orphans). This can # help prevent users being presented with pages contain only a few # results. self._orphans = orphans # Count the total results being paginated self._items_count = frame_cls.count(self._filter) # Calculated the number of pages total = self._items_count - orphans self._page_count = max(1, int(math.ceil(total / float(self._per_page)))) # Create a list of page number that can be used to navigate the results self._page_numbers = range(1, self._page_count + 1)
def cascade(cls, ref_cls, field, frames): """Apply a cascading delete (does not emit signals)""" from mongoframes.queries import to_refs ids = [to_refs(f[field]) for f in frames if f.get(field)] ref_cls.get_collection().delete_many({'_id': {'$in': ids}})