Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOCS-13309 short circuit evaluation #5780

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions source/includes/and-or-behavior.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
To allow the query engine to optimize queries, |and-or| handles
errors as follows:

- If any expression supplied to |and-or| would cause an error when
evaluated alone, the |and-or| containing the expression may cause an
error but an error is not guaranteed.

- An expression supplied after the first expression supplied to |and-or|
may cause an error even if the first expression evaluates to
|true-false|.

For example, the following query *always* produces an error if ``$x`` is
``0``:

.. code-block:: javascript

db.example.find( {
$expr: { $eq: [ { $divide: [ 1, "$x" ] }, 3 ] }
} )

The following query, which contains multiple expressions supplied to
|and-or|, *may* produce an error if there is any document where ``$x``
is ``0``:
30 changes: 22 additions & 8 deletions source/reference/operator/aggregation/and.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ Definition
.. expression:: $and

Evaluates one or more expressions and returns ``true`` if *all* of
the expressions are ``true`` or if evoked with no argument
the expressions are ``true`` or if run with no argument
expressions. Otherwise, :expression:`$and` returns ``false``.

:expression:`$and` has the following syntax:
:expression:`$and` syntax:

.. code-block:: javascript

Expand All @@ -33,9 +33,6 @@ Definition
Behavior
--------

:expression:`$and` uses short-circuit logic: the operation stops
evaluation after encountering the first ``false`` expression.

.. include:: /includes/extracts/fact-agg-boolean-and.rst

.. list-table::
Expand Down Expand Up @@ -66,10 +63,27 @@ evaluation after encountering the first ``false`` expression.

- ``false``

Error Handling
--------------
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Jason, sorry for not being clearer in my comment. I meant to make these sub-headings of the "Behavior" section above.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(discussion resolved via Slack. no action needed).


.. |and-or| replace:: ``$and``
.. |true-false| replace:: ``false``

.. include:: /includes/and-or-behavior.rst

.. code-block:: javascript

db.example.find( {
$and: [
{ x: { $ne: 0 } },
{ $expr: { $eq: [ { $divide: [ 1, "$x" ] }, 3 ] } }
]
} )

Example
-------

Create an example ``inventory`` collection with the following documents:
Create an example ``inventory`` collection with these documents:

.. code-block:: javascript

Expand All @@ -81,7 +95,7 @@ Create an example ``inventory`` collection with the following documents:
{ "_id" : 5, "item" : "VWZ2", description: "product 5", qty: 180 }
])

The following operation uses the :expression:`$and` operator to
This operation uses the :expression:`$and` operator to
determine if ``qty`` is greater than 100 *and* less than ``250``:

.. code-block:: javascript
Expand All @@ -99,7 +113,7 @@ determine if ``qty`` is greater than 100 *and* less than ``250``:
]
)

The operation returns the following results:
The operation returns these results:

.. code-block:: javascript

Expand Down
20 changes: 17 additions & 3 deletions source/reference/operator/aggregation/or.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ Definition
Behavior
--------

:expression:`$or` uses short-circuit logic: the operation stops
evaluation after encountering the first ``true`` expression.

.. include:: /includes/extracts/fact-agg-boolean-or.rst

.. list-table::
Expand All @@ -60,6 +57,23 @@ evaluation after encountering the first ``true`` expression.

- ``false``

Error Handling
--------------
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest converting to a sub-heading of the Behavior section above.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(discussion resolved via Slack. no action needed).


.. |and-or| replace:: ``$or``
.. |true-false| replace:: ``true``

.. include:: /includes/and-or-behavior.rst

.. code-block:: javascript

db.example.find( {
$or: [
{ x: { $eq: 0 } },
{ $expr: { $eq: [ { $divide: [ 1, "$x" ] }, 3 ] } }
]
} )

Example
-------

Expand Down
45 changes: 28 additions & 17 deletions source/reference/operator/query/and.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,51 @@ $and

*Syntax*: ``{ $and: [ { <expression1> }, { <expression2> } , ... , { <expressionN> } ] }``

:query:`$and` performs a logical ``AND`` operation on an array
of *one or more* expressions (e.g. ``<expression1>``,
``<expression2>``, etc.) and selects the documents that satisfy
*all* the expressions in the array. The :query:`$and` operator
uses *short-circuit evaluation*. If the first expression
(e.g. ``<expression1>``) evaluates to ``false``, MongoDB will not
evaluate the remaining expressions.
:query:`$and` performs a logical ``AND`` operation on an array of
*one or more* expressions (``<expression1>``, ``<expression2>``, and
so on) and selects the documents that satisfy *all* the expressions.

.. note::

MongoDB provides an implicit ``AND`` operation when specifying a
comma separated list of expressions.

Behavior
--------

.. |and-or| replace:: ``$and``
.. |true-false| replace:: ``false``

.. include:: /includes/and-or-behavior.rst

.. code-block:: javascript

db.example.find( {
$and: [
{ x: { $ne: 0 } },
{ $expr: { $eq: [ { $divide: [ 1, "$x" ] }, 3 ] } }
]
} )

Examples
--------

``AND`` Queries With Multiple Expressions Specifying the Same Field
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Consider the following example:
Consider this query:

.. code-block:: javascript

db.inventory.find( { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } } ] } )

This query will select all documents in the ``inventory``
collection where:
The query selects all documents in the ``inventory`` collection where:

- the ``price`` field value is not equal to ``1.99`` **and**
- the ``price`` field exists.

This query can be also be constructed with an implicit ``AND``
operation by combining the operator expressions for the ``price``
field. For example, this query can be written as:
The query can be rewritten with an implicit ``AND`` operation that
combines the operator expressions for the ``price`` field:

.. code-block:: javascript

Expand All @@ -56,7 +67,7 @@ field. For example, this query can be written as:
``AND`` Queries With Multiple Expressions Specifying the Same Operator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Consider the following example:
Consider this query:

.. code-block:: javascript

Expand All @@ -67,14 +78,14 @@ Consider the following example:
]
} )

This query will select all documents where:
The query selects all documents where:

- the ``qty`` field value is less than ``10`` or greater than ``50``, **and**
- the ``sale`` field value is equal to ``true`` **or** the ``price``
field value is less than ``5``.

This query cannot be constructed using an implicit ``AND`` operation,
because it uses the :query:`$or` operator more than once.
The query cannot use an implicit ``AND`` operation because it uses the
:query:`$or` operator more than once.

.. seealso::

Expand Down
17 changes: 17 additions & 0 deletions source/reference/operator/query/or.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,20 @@ You may nest :query:`$or` operations.
- :method:`~db.collection.find()`
- :method:`~cursor.sort()`
- :query:`$in`

Error Handling
~~~~~~~~~~~~~~

.. |and-or| replace:: ``$or``
.. |true-false| replace:: ``true``

.. include:: /includes/and-or-behavior.rst

.. code-block:: javascript

db.example.find( {
$or: [
{ x: { $eq: 0 } },
{ $expr: { $eq: [ { $divide: [ 1, "$x" ] }, 3 ] } }
]
} )