Skip to content

Commit 6be1b86

Browse files
authored
Merge branch '2.10.x' into 2.9.x-merge-up-into-2.10.x_lOGTcPMg
2 parents 8f0b370 + bf9f889 commit 6be1b86

File tree

115 files changed

+1195
-1241
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+1195
-1241
lines changed

.doctrine-project.json

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,31 @@
66
"docsSlug": "doctrine-mongodb-odm",
77
"versions": [
88
{
9-
"name": "2.9",
10-
"branchName": "2.9.x",
9+
"name": "2.10",
10+
"branchName": "2.10.x",
1111
"slug": "latest",
1212
"upcoming": true,
1313
"aliases": [
14+
"2.10.x"
15+
]
16+
},
17+
{
18+
"name": "2.9",
19+
"branchName": "2.9.x",
20+
"slug": "2.9",
21+
"current": true,
22+
"aliases": [
23+
"current",
24+
"stable",
1425
"2.9.x"
1526
]
1627
},
1728
{
1829
"name": "2.8",
1930
"branchName": "2.8.x",
2031
"slug": "2.8",
21-
"current": true,
32+
"maintained": false,
2233
"aliases": [
23-
"current",
24-
"stable",
2534
"2.8.x"
2635
]
2736
},

.github/workflows/coding-standards.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ on:
1111
jobs:
1212
coding-standards:
1313
name: "Coding Standards"
14-
uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.0.1"
14+
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.1.0"

.github/workflows/continuous-integration.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
- "8.1"
2222
- "8.2"
2323
- "8.3"
24+
- "8.4"
2425
mongodb-version:
2526
- "7.0"
2627
- "6.0"
@@ -105,8 +106,6 @@ jobs:
105106
if: "${{ matrix.symfony-version == '7' }}"
106107
run: |
107108
composer config minimum-stability dev
108-
# not yet ready for v7
109-
composer remove --no-update --dev vimeo/psalm
110109
# update symfony deps
111110
composer require --no-update symfony/console:^7@dev
112111
composer require --no-update symfony/var-dumper:^7@dev

.github/workflows/release-on-milestone-closed.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
jobs:
99
release:
1010
name: "Git tag, release & create merge-up PR"
11-
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@5.0.1"
11+
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.1.0"
1212
secrets:
1313
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
1414
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}

.github/workflows/static-analysis.yml

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -59,36 +59,3 @@ jobs:
5959

6060
- name: "Run a static analysis with phpstan/phpstan"
6161
run: "vendor/bin/phpstan analyse --error-format=github"
62-
63-
static-analysis-psalm:
64-
name: "Static Analysis with Psalm"
65-
runs-on: "ubuntu-22.04"
66-
67-
strategy:
68-
matrix:
69-
php-version:
70-
- "8.2"
71-
72-
steps:
73-
- name: "Checkout code"
74-
uses: "actions/checkout@v4"
75-
76-
- name: "Install PHP"
77-
uses: "shivammathur/setup-php@v2"
78-
with:
79-
coverage: "none"
80-
extensions: "mongodb"
81-
php-version: "${{ matrix.php-version }}"
82-
83-
- name: "Install dependencies with Composer"
84-
uses: "ramsey/composer-install@v3"
85-
86-
- name: "Upload composer.lock as build artifact"
87-
uses: actions/upload-artifact@v4
88-
with:
89-
name: "composer-lock-static-analysis-psalm"
90-
path: composer.lock
91-
overwrite: true
92-
93-
- name: "Run a static analysis with vimeo/psalm"
94-
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ vendor/
1111
.phpunit.cache
1212
.phpunit.result.cache
1313
phpcs.xml
14-
psalm.xml

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@
4747
"phpstan/phpstan-phpunit": "^1.0",
4848
"phpunit/phpunit": "^10.4",
4949
"squizlabs/php_codesniffer": "^3.5",
50-
"symfony/cache": "^5.4 || ^6.0 || ^7.0",
51-
"vimeo/psalm": "~5.24.0"
50+
"symfony/cache": "^5.4 || ^6.0 || ^7.0"
5251
},
5352
"conflict": {
5453
"doctrine/annotations": "<1.12 || >=3.0"

docs/en/cookbook/simple-search-engine.rst

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Simple Search Engine
33

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

99
Sample Model: Product
@@ -25,15 +25,9 @@ setup a document like the following with a ``$keywords`` property that is mapped
2525
#[Field(type: 'string')]
2626
public string $title;
2727
28-
/** @var Collection<string> */
2928
#[Field(type: 'collection')]
3029
#[Index]
31-
public Collection $keywords;
32-
33-
public function __construct()
34-
{
35-
$this->keywords = new ArrayCollection();
36-
}
30+
public array $keywords = [];
3731
}
3832
3933
Working with Keywords
@@ -47,11 +41,11 @@ Now, create a product and add some keywords:
4741
4842
$product = new Product();
4943
$product->title = 'Nike Air Jordan 2011';
50-
$product->keywords->add('nike shoes');
51-
$product->keywords->add('jordan shoes');
52-
$product->keywords->add('air jordan');
53-
$product->keywords->add('shoes');
54-
$product->keywords->add('2011');
44+
$product->keywords[] = 'nike shoes';
45+
$product->keywords[] = 'jordan shoes';
46+
$product->keywords[] = 'air jordan';
47+
$product->keywords[] = 'shoes';
48+
$product->keywords[] = '2011';
5549
5650
$dm->persist($product);
5751
$dm->flush();
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
Storing Time Series Data
2+
========================
3+
4+
.. note::
5+
6+
Support for mapping time series data was added in ODM 2.10.
7+
8+
`time-series data <https://www.mongodb.com/docs/manual/core/timeseries-collections/>`__
9+
is a sequence of data points in which insights are gained by analyzing changes
10+
over time.
11+
12+
Time series data is generally composed of these components:
13+
14+
-
15+
Time when the data point was recorded
16+
17+
-
18+
Metadata, which is a label, tag, or other data that identifies a data series
19+
and rarely changes
20+
21+
-
22+
Measurements, which are the data points tracked at increments in time.
23+
24+
A time series document always contains a time value, and one or more measurement
25+
fields. Metadata is optional, but cannot be added to a time series collection
26+
after creating it. When using an embedded document for metadata, fields can be
27+
added to this document after creating the collection.
28+
29+
.. note::
30+
31+
Support for time series collections was added in MongoDB 5.0. Attempting to
32+
use this functionality on older server versions will result in an error on
33+
schema creation.
34+
35+
Creating The Model
36+
------------------
37+
38+
For this example, we'll be storing data from multiple sensors measuring
39+
temperature and humidity. Other examples for time series include stock data,
40+
price information, website visitors, or vehicle telemetry (speed, position,
41+
etc.).
42+
43+
First, we define the model for our data:
44+
45+
.. code-block:: php
46+
47+
<?php
48+
49+
use DateTimeImmutable;
50+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
51+
use MongoDB\BSON\ObjectId;
52+
53+
#[ODM\Document]
54+
readonly class Measurement
55+
{
56+
#[ODM\Id]
57+
public string $id;
58+
59+
public function __construct(
60+
#[ODM\Field(type: 'date_immutable')]
61+
public DateTimeImmutable $time,
62+
#[ODM\Field(type: 'int')]
63+
public int $sensorId,
64+
#[ODM\Field(type: 'float')]
65+
public float $temperature,
66+
#[ODM\Field(type: 'float')]
67+
public float $humidity,
68+
) {
69+
$this->id = (string) new ObjectId();
70+
}
71+
}
72+
73+
Note that we defined the entire model as readonly. While we could theoretically
74+
change values in the document, in this example we'll assume that the data will
75+
not change.
76+
77+
Now we can mark the document as a time series document. To do so, we use the
78+
``TimeSeries`` attribute, configuring appropriate values for the time and
79+
metadata field, which in our case stores the ID of the sensor reporting the
80+
measurement:
81+
82+
.. code-block:: php
83+
84+
<?php
85+
86+
// ...
87+
88+
#[ODM\Document]
89+
#[ODM\TimeSeries(timeField: 'time', metaField: 'sensorId')]
90+
readonly class Measurement
91+
{
92+
// ...
93+
}
94+
95+
Once we create the schema, we can store our measurements in this time series
96+
collection and let MongoDB optimize the storage for faster queries:
97+
98+
.. code-block:: php
99+
100+
<?php
101+
102+
$measurement = new Measurement(
103+
time: new DateTimeImmutable(),
104+
sensorId: $sensorId,
105+
temperature: $temperature,
106+
humidity: $humidity,
107+
);
108+
109+
$documentManager->persist($measurement);
110+
$documentManager->flush();
111+
112+
Note that other functionality such as querying, using aggregation pipelines, or
113+
removing data works the same as with other collections.
114+
115+
Considerations
116+
--------------
117+
118+
With the mapping above, data is stored with a granularity of seconds. Depending
119+
on how often measurements come in, we can reduce the granularity to minutes or
120+
hours. This changes how the data is stored internally by changing the bucket
121+
size. This affects storage requirements and query performance.
122+
123+
For example, with the default ``seconds`` granularity, each bucket groups
124+
documents for one hour. If each sensor only reports data every few minutes, we'd
125+
do well to configure ``minute`` granularity. This reduces the
126+
number of buckets created, reducing storage and making queries more efficient.
127+
However, if we were to choose ``hours`` for granularity, readings for a whole
128+
month would be grouped into one bucket, resulting in slower queries as more
129+
entries have to be traversed when reading data.
130+
131+
More details on granularity and other consideration scan be found in the
132+
`MongoDB documentation <https://www.mongodb.com/docs/manual/core/timeseries/timeseries-considerations/>`__.

docs/en/reference/attributes-reference.rst

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,64 @@ for sharding the document collection.
11441144
//...
11451145
}
11461146
1147+
#[TimeSeries]
1148+
-------------
1149+
1150+
This attribute may be used at the class level to mark a collection as containing
1151+
:doc:`time-series data <../cookbook/time-series-data>`.
1152+
1153+
.. code-block:: php
1154+
1155+
<?php
1156+
1157+
use Doctrine\ODM\MongoDB\Mapping\TimeSeries\Granularity;
1158+
1159+
#[Document]
1160+
#[TimeSeries(timeField: 'time', metaField: 'metadata', granularity: Granularity::Seconds)]
1161+
class Measurements
1162+
{
1163+
#[Id]
1164+
public string $id;
1165+
1166+
#[Field]
1167+
public DateTimeImmutable $time;
1168+
1169+
#[EmbedOne(targetDocument: MeasurementMetadata)]
1170+
public MeasurementMetadata $metadata;
1171+
1172+
#[Field]
1173+
public int $measurement;
1174+
}
1175+
1176+
The ``timeField`` attribute is required and denotes the field where the time of
1177+
a time series entry is stored. The following optional attributes may be set:
1178+
1179+
-
1180+
``metaField`` - The name of the field which contains metadata in each time
1181+
series document. The field can be of any data type.
1182+
1183+
-
1184+
``granularity`` - Set the granularity to the value that most closely matches
1185+
the time between consecutive incoming timestamps. This allows MongoDB to
1186+
optimize how data is stored. Note: this attribute cannot be combined with
1187+
``bucketMaxSpanSeconds`` and ``bucketRoundingSeconds``.
1188+
1189+
-
1190+
``bucketMaxSpanSeconds`` - Used with ``bucketRoundingSeconds`` as an
1191+
alternative to ``granularity``. Sets the maximum time between timestamps
1192+
in the same bucket. Possible values are 1 - 31356000.
1193+
1194+
-
1195+
``bucketRoundingSeconds`` - Used with ``bucketMaxSpanSeconds``, must be set
1196+
to the same value as ``bucketMaxSpanSeconds``. When a document requires a
1197+
new bucket, MongoDB rounds down the document's timestamp value by this
1198+
interval to set the minimum time for the bucket.
1199+
1200+
-
1201+
``expireAfterSeconds`` - Enables the automatic deletion of documents in a
1202+
time series collection by specifying the number of seconds after which
1203+
documents expire. MongoDB deletes these expired documents automatically.
1204+
11471205
#[UniqueIndex]
11481206
--------------
11491207

@@ -1177,7 +1235,7 @@ for the related collection.
11771235
`Extended JSON specification <https://github.com/mongodb/specifications/blob/master/source/extended-json.rst>`_.
11781236
The recommended way to fill up this property is to create a class constant
11791237
(eg. ``::VALIDATOR``) using the
1180-
`HEREDOC/NOWDOC syntax <https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.nowdoc>`_
1238+
`HEREDOC/NOWDOC syntax <https://www.php.net/language.types.string#language.types.string.syntax.nowdoc>`_
11811239
for clarity and to reference it as the attribute value.
11821240
-
11831241
``action`` - Determines how MongoDB handles documents that violate
@@ -1340,6 +1398,6 @@ root class specified in the view mapping.
13401398
.. _BSON specification: http://bsonspec.org/spec.html
13411399
.. _DBRef: https://docs.mongodb.com/manual/reference/database-references/#dbrefs
13421400
.. _geoNear command: https://docs.mongodb.com/manual/reference/command/geoNear/
1343-
.. _MongoDB\BSON\ObjectId: https://www.php.net/manual/en/class.mongodb-bson-objectid.php
1401+
.. _MongoDB\BSON\ObjectId: https://www.php.net/class.mongodb-bson-objectid
13441402
.. |FQCN| raw:: html
13451403
<abbr title="Fully-Qualified Class Name">FQCN</abbr>

0 commit comments

Comments
 (0)