Skip to content

Commit

Permalink
Improvements of doc and tests related with recent timeseries collecti…
Browse files Browse the repository at this point in the history
…on support
  • Loading branch information
bagerard committed Aug 25, 2024
1 parent 64c28ef commit 889096c
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 32 deletions.
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Development
- (Fill this out as you fix issues and develop your features).
- Allow gt/gte/lt/lte/ne operators to be used with a list as value on ListField #2813
- Switch tox to use pytest instead of legacy `python setup.py test` #2804
- Add support for timeseries collection #2661

Changes in 0.28.2
=================
Expand Down
20 changes: 20 additions & 0 deletions docs/guide/defining-documents.rst
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,26 @@ The following example shows a :class:`Log` document that will be limited to
ip_address = StringField()
meta = {'max_documents': 1000, 'max_size': 2000000}

Timeseries collections
------------------
A :class:`~mongoengine.Document` may use a **Timeseries Collection** by specifying
:attr:`timeseries` in the :attr:`meta` dictionary. Timeseries collection were added
in MongoDB 5.0 (`doc <https://www.mongodb.com/docs/v5.3/core/timeseries-collections/>`_).
The following example shows a Document class with a basic setup::

class SensorData(Document):
timestamp = DateTimeField(required=True)
temperature = FloatField()

meta = {
"timeseries": {
"timeField": "timestamp",
"metaField": "temperature",
"granularity": "seconds",
"expireAfterSeconds": 5,
},
}

.. defining-indexes_
Indexes
Expand Down
34 changes: 7 additions & 27 deletions tests/document/test_timeseries_collection.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
import unittest
from datetime import datetime, timedelta

Expand Down Expand Up @@ -102,9 +103,7 @@ def test_timeseries_expiration(self):
assert collection.count_documents({}) == 1

# Wait for more than the expiration time
import time

time.sleep(3)
time.sleep(2)
assert collection.count_documents({}) > 0

@requires_mongodb_gte_50
Expand Down Expand Up @@ -135,12 +134,8 @@ class SensorDataWithIndex(Document):

indexes = collection.index_information()

assert (
"timestamp_index" in indexes
), "Index on 'timestamp' field was not created"
assert (
"temperature_index" in indexes
), "Index on 'temperature' field was not created"
assert "timestamp_index" in indexes
assert "temperature_index" in indexes

@requires_mongodb_gte_50
def test_timeseries_data_insertion_order(self):
Expand All @@ -158,9 +153,9 @@ def test_timeseries_data_insertion_order(self):

# Check the insertion order
assert len(documents) == 3
assert documents[0].temperature == 22.0 # Earliest document
assert documents[1].temperature == 23.4 # Middle document
assert documents[2].temperature == 24.0 # Latest document
assert documents[0].temperature == 22.0
assert documents[1].temperature == 23.4
assert documents[2].temperature == 24.0

@requires_mongodb_gte_50
def test_timeseries_query_by_time_range(self):
Expand All @@ -182,21 +177,6 @@ def test_timeseries_query_by_time_range(self):
assert documents[0].temperature == 23.0
assert documents[1].temperature == 24.0

@requires_mongodb_gte_50
def test_timeseries_large_data_volume(self):
"""Ensure that the time-series collection can handle a large volume of data insertion."""

self.SensorData._get_collection_name()
collection = self.SensorData._get_collection()

for i in range(10000):
self.SensorData(
timestamp=datetime.utcnow() - timedelta(seconds=i),
temperature=20.0 + i % 5,
).save()

assert collection.count_documents({}) == 10000


if __name__ == "__main__":
unittest.main()
10 changes: 5 additions & 5 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import functools
import operator
import unittest

Expand Down Expand Up @@ -77,14 +78,13 @@ def requires_mongodb_gte_36(func):
:param oper: The operator to apply (e.g. operator.ge)
"""

@functools.wraps(func)
def _inner(*args, **kwargs):
mongodb_v = get_mongodb_version()
if oper(mongodb_v, mongo_version_req):
return func(*args, **kwargs)
else:
pretty_version = ".".join(str(n) for n in mongo_version_req)
pytest.skip(f"Needs MongoDB {oper.__name__} v{pretty_version}")

pretty_version = ".".join(str(n) for n in mongo_version_req)
pytest.skip(f"Needs MongoDB {oper.__name__} v{pretty_version}")

_inner.__name__ = func.__name__
_inner.__doc__ = func.__doc__
return _inner

0 comments on commit 889096c

Please sign in to comment.