Skip to content

Commit

Permalink
Merge branch '2.10.x' into 2.9.x-merge-up-into-2.10.x_xBlWiFM2
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN committed Dec 19, 2024
2 parents ad7827c + 7d6d710 commit dc306ed
Show file tree
Hide file tree
Showing 109 changed files with 1,189 additions and 1,222 deletions.
19 changes: 14 additions & 5 deletions .doctrine-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,31 @@
"docsSlug": "doctrine-mongodb-odm",
"versions": [
{
"name": "2.9",
"branchName": "2.9.x",
"name": "2.10",
"branchName": "2.10.x",
"slug": "latest",
"upcoming": true,
"aliases": [
"2.10.x"
]
},
{
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"current": true,
"aliases": [
"current",
"stable",
"2.9.x"
]
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"current": true,
"maintained": false,
"aliases": [
"current",
"stable",
"2.8.x"
]
},
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/coding-standards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ on:
jobs:
coding-standards:
name: "Coding Standards"
uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.0.1"
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.1.0"
3 changes: 1 addition & 2 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
- "8.1"
- "8.2"
- "8.3"
- "8.4"
mongodb-version:
- "7.0"
- "6.0"
Expand Down Expand Up @@ -105,8 +106,6 @@ jobs:
if: "${{ matrix.symfony-version == '7' }}"
run: |
composer config minimum-stability dev
# not yet ready for v7
composer remove --no-update --dev vimeo/psalm
# update symfony deps
composer require --no-update symfony/console:^7@dev
composer require --no-update symfony/var-dumper:^7@dev
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-on-milestone-closed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
release:
name: "Git tag, release & create merge-up PR"
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@5.0.1"
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.1.0"
secrets:
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
Expand Down
33 changes: 0 additions & 33 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,36 +59,3 @@ jobs:

- name: "Run a static analysis with phpstan/phpstan"
run: "vendor/bin/phpstan analyse --error-format=github"

static-analysis-psalm:
name: "Static Analysis with Psalm"
runs-on: "ubuntu-22.04"

strategy:
matrix:
php-version:
- "8.2"

steps:
- name: "Checkout code"
uses: "actions/checkout@v4"

- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
extensions: "mongodb"
php-version: "${{ matrix.php-version }}"

- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v3"

- name: "Upload composer.lock as build artifact"
uses: actions/upload-artifact@v4
with:
name: "composer-lock-static-analysis-psalm"
path: composer.lock
overwrite: true

- name: "Run a static analysis with vimeo/psalm"
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ vendor/
.phpunit.cache
.phpunit.result.cache
phpcs.xml
psalm.xml
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^10.4",
"squizlabs/php_codesniffer": "^3.5",
"symfony/cache": "^5.4 || ^6.0 || ^7.0",
"vimeo/psalm": "~5.24.0"
"symfony/cache": "^5.4 || ^6.0 || ^7.0"
},
"conflict": {
"doctrine/annotations": "<1.12 || >=3.0"
Expand Down
20 changes: 7 additions & 13 deletions docs/en/cookbook/simple-search-engine.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Simple Search Engine

It is very easy to implement a simple keyword search engine with MongoDB. Because of
its flexible schema less nature we can store the keywords we want to search through directly
on the document. MongoDB is capable of indexing the embedded documents so the results are fast
on the document. MongoDB is capable of indexing an array field, so the results are fast
and scalable.

Sample Model: Product
Expand All @@ -25,15 +25,9 @@ setup a document like the following with a ``$keywords`` property that is mapped
#[Field(type: 'string')]
public string $title;
/** @var Collection<string> */
#[Field(type: 'collection')]
#[Index]
public Collection $keywords;
public function __construct()
{
$this->keywords = new ArrayCollection();
}
public array $keywords = [];
}
Working with Keywords
Expand All @@ -47,11 +41,11 @@ Now, create a product and add some keywords:
$product = new Product();
$product->title = 'Nike Air Jordan 2011';
$product->keywords->add('nike shoes');
$product->keywords->add('jordan shoes');
$product->keywords->add('air jordan');
$product->keywords->add('shoes');
$product->keywords->add('2011');
$product->keywords[] = 'nike shoes';
$product->keywords[] = 'jordan shoes';
$product->keywords[] = 'air jordan';
$product->keywords[] = 'shoes';
$product->keywords[] = '2011';
$dm->persist($product);
$dm->flush();
Expand Down
132 changes: 132 additions & 0 deletions docs/en/cookbook/time-series-data.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
Storing Time Series Data
========================

.. note::

Support for mapping time series data was added in ODM 2.10.

`time-series data <https://www.mongodb.com/docs/manual/core/timeseries-collections/>`__
is a sequence of data points in which insights are gained by analyzing changes
over time.

Time series data is generally composed of these components:

-
Time when the data point was recorded

-
Metadata, which is a label, tag, or other data that identifies a data series
and rarely changes

-
Measurements, which are the data points tracked at increments in time.

A time series document always contains a time value, and one or more measurement
fields. Metadata is optional, but cannot be added to a time series collection
after creating it. When using an embedded document for metadata, fields can be
added to this document after creating the collection.

.. note::

Support for time series collections was added in MongoDB 5.0. Attempting to
use this functionality on older server versions will result in an error on
schema creation.

Creating The Model
------------------

For this example, we'll be storing data from multiple sensors measuring
temperature and humidity. Other examples for time series include stock data,
price information, website visitors, or vehicle telemetry (speed, position,
etc.).

First, we define the model for our data:

.. code-block:: php
<?php
use DateTimeImmutable;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use MongoDB\BSON\ObjectId;
#[ODM\Document]
readonly class Measurement
{
#[ODM\Id]
public string $id;
public function __construct(
#[ODM\Field(type: 'date_immutable')]
public DateTimeImmutable $time,
#[ODM\Field(type: 'int')]
public int $sensorId,
#[ODM\Field(type: 'float')]
public float $temperature,
#[ODM\Field(type: 'float')]
public float $humidity,
) {
$this->id = (string) new ObjectId();
}
}
Note that we defined the entire model as readonly. While we could theoretically
change values in the document, in this example we'll assume that the data will
not change.

Now we can mark the document as a time series document. To do so, we use the
``TimeSeries`` attribute, configuring appropriate values for the time and
metadata field, which in our case stores the ID of the sensor reporting the
measurement:

.. code-block:: php
<?php
// ...
#[ODM\Document]
#[ODM\TimeSeries(timeField: 'time', metaField: 'sensorId')]
readonly class Measurement
{
// ...
}
Once we create the schema, we can store our measurements in this time series
collection and let MongoDB optimize the storage for faster queries:

.. code-block:: php
<?php
$measurement = new Measurement(
time: new DateTimeImmutable(),
sensorId: $sensorId,
temperature: $temperature,
humidity: $humidity,
);
$documentManager->persist($measurement);
$documentManager->flush();
Note that other functionality such as querying, using aggregation pipelines, or
removing data works the same as with other collections.

Considerations
--------------

With the mapping above, data is stored with a granularity of seconds. Depending
on how often measurements come in, we can reduce the granularity to minutes or
hours. This changes how the data is stored internally by changing the bucket
size. This affects storage requirements and query performance.

For example, with the default ``seconds`` granularity, each bucket groups
documents for one hour. If each sensor only reports data every few minutes, we'd
do well to configure ``minute`` granularity. This reduces the
number of buckets created, reducing storage and making queries more efficient.
However, if we were to choose ``hours`` for granularity, readings for a whole
month would be grouped into one bucket, resulting in slower queries as more
entries have to be traversed when reading data.

More details on granularity and other consideration scan be found in the
`MongoDB documentation <https://www.mongodb.com/docs/manual/core/timeseries/timeseries-considerations/>`__.
58 changes: 58 additions & 0 deletions docs/en/reference/attributes-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,64 @@ for sharding the document collection.
//...
}
#[TimeSeries]
-------------

This attribute may be used at the class level to mark a collection as containing
:doc:`time-series data <../cookbook/time-series-data>`.

.. code-block:: php
<?php
use Doctrine\ODM\MongoDB\Mapping\TimeSeries\Granularity;
#[Document]
#[TimeSeries(timeField: 'time', metaField: 'metadata', granularity: Granularity::Seconds)]
class Measurements
{
#[Id]
public string $id;
#[Field]
public DateTimeImmutable $time;
#[EmbedOne(targetDocument: MeasurementMetadata)]
public MeasurementMetadata $metadata;
#[Field]
public int $measurement;
}
The ``timeField`` attribute is required and denotes the field where the time of
a time series entry is stored. The following optional attributes may be set:

-
``metaField`` - The name of the field which contains metadata in each time
series document. The field can be of any data type.

-
``granularity`` - Set the granularity to the value that most closely matches
the time between consecutive incoming timestamps. This allows MongoDB to
optimize how data is stored. Note: this attribute cannot be combined with
``bucketMaxSpanSeconds`` and ``bucketRoundingSeconds``.

-
``bucketMaxSpanSeconds`` - Used with ``bucketRoundingSeconds`` as an
alternative to ``granularity``. Sets the maximum time between timestamps
in the same bucket. Possible values are 1 - 31356000.

-
``bucketRoundingSeconds`` - Used with ``bucketMaxSpanSeconds``, must be set
to the same value as ``bucketMaxSpanSeconds``. When a document requires a
new bucket, MongoDB rounds down the document's timestamp value by this
interval to set the minimum time for the bucket.

-
``expireAfterSeconds`` - Enables the automatic deletion of documents in a
time series collection by specifying the number of seconds after which
documents expire. MongoDB deletes these expired documents automatically.

#[UniqueIndex]
--------------

Expand Down
25 changes: 25 additions & 0 deletions doctrine-mongo-mapping.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<xs:element name="shard-key" type="odm:shard-key" minOccurs="0" />
<xs:element name="read-preference" type="odm:read-preference" minOccurs="0" />
<xs:element name="schema-validation" type="odm:schema-validation" minOccurs="0" />
<xs:element name="time-series" type="odm:time-series" minOccurs="0" />
</xs:choice>

<xs:attribute name="db" type="xs:NMTOKEN" />
Expand Down Expand Up @@ -634,4 +635,28 @@
</xs:restriction>
</xs:simpleType>

<xs:complexType name="time-series">
<xs:attribute name="time-field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="meta-field" type="xs:NMTOKEN" />
<xs:attribute name="granularity" type="odm:time-series-granularity" />
<xs:attribute name="expire-after-seconds" type="xs:integer" />
<xs:attribute name="bucket-max-span-seconds" type="odm:time-series-group-seconds" />
<xs:attribute name="bucket-rounding-seconds" type="odm:time-series-group-seconds" />
</xs:complexType>

<xs:simpleType name="time-series-granularity">
<xs:restriction base="xs:token">
<xs:enumeration value="seconds" />
<xs:enumeration value="minutes" />
<xs:enumeration value="hours" />
</xs:restriction>
</xs:simpleType>

<xs:simpleType name="time-series-group-seconds">
<xs:restriction base="xs:integer">
<xs:minInclusive value="1" />
<xs:maxInclusive value="31536000" />
</xs:restriction>
</xs:simpleType>

</xs:schema>
Loading

0 comments on commit dc306ed

Please sign in to comment.