Skip to content

Commit

Permalink
DOCSP-34044: Add bitwise operators to aggregation pipeline (#253)
Browse files Browse the repository at this point in the history
* changing code + checkpint

* very preliminary first draft

* correct code block

* code blocks

* and and or

* xor, not, and other small tweaks

* changing variable type in linq.cs

* never mind

* back to double

* addressing basic comments

* move code to include

* io code block

* reworking first sentence

* bullet list

* bullet list pt 2

* bullet list pt 3

* feedback

* nits

* change example

* correction

* snake case

* refining note

* vale

(cherry picked from commit a1b1f4c)
  • Loading branch information
mayaraman19 committed Oct 24, 2024
1 parent bc8bb6d commit a2e62bd
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/vale-tdbx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ jobs:
- name: checkout
uses: actions/checkout@master

- name: Install docutils
run: sudo apt-get install -y docutils

- id: files
uses: masesgroup/retrieve-changed-files@v2
with:
Expand Down
184 changes: 180 additions & 4 deletions source/fundamentals/linq.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LINQ
.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:depth: 3
:class: singlecol

.. facet::
Expand Down Expand Up @@ -68,10 +68,11 @@ object that links to the collection. To create the object, use the ``AsQueryable
as follows:

.. code-block:: csharp
:emphasize-lines: 2
:emphasize-lines: 3

var restaurantsCollection = restaurantsDatabase.GetCollection<Restaurant>("restaurants");
var queryableCollection = restaurantsCollection.AsQueryable();
var restaurantsDatabase = client.GetDatabase("sample_restaurants");
var restaurantsCollection = restaurantsDatabase.GetCollection<Restaurant>("restaurants");
var queryableCollection = restaurantsCollection.AsQueryable();

The ``AsQueryable()`` method returns an `IMongoQueryable
<{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.Linq.IMongoQueryable.html>`__ instance that
Expand Down Expand Up @@ -587,6 +588,181 @@ in the Atlas manual. For more examples about running Atlas Vector Search queries
{+driver-short+}, see :atlas:`Run Vector Search Queries </atlas-vector-search/vector-search-stage/>`
in the Atlas manual and select :guilabel:`C#` from the language dropdown.

Bitwise Operators
~~~~~~~~~~~~~~~~~

This section describes the :wikipedia:`bitwise operators <Bitwise_operation>`
supported by the {+driver-short+} that you can use in an aggregation pipeline.
You can use multiple bitwise operators in the same
stage. The following guidelines apply when using bitwise operators:

- All operands must be of type ``int`` or ``long``.

- ``$bitAnd``, ``$bitOr``, and ``$bitXor`` take two or more operands. ``$bitNot`` takes one operand.

- Bitwise operations are evaluated from left to right.

The examples in this section use the following documents in a collection called
``ingredients``:

.. code-block:: json

{ "_id" : 1, "name" : "watermelon", "is_available" : 1, "is_cheap" : 1 },
{ "_id" : 2, "name" : "onions", "is_available" : 1, "is_cheap" : 0 },
{ "_id" : 3, "name" : "eggs", "is_available" : 0, "is_cheap" : 0 },
{ "_id" : 4, "name" : "potatoes", "is_available" : 1, "is_cheap" : 1 },
{ "_id" : 5, "name" : "pasta", "is_available" : 0, "is_cheap" : 1 },
{ "_id" : 6, "name" : "cheese", "is_available" : 1 }

The ``"is_available"`` field represents if an ingredient is available. If this
field has a value of ``0``, the ingredient is not available. If it has a value
of ``1``, the ingredient is available.

The ``"is_cheap"`` field represents if an ingredient is cheap. If this field has
a value of ``0``, the ingredient is not cheap. If it has a value of ``1``, the
ingredient is cheap.

The following ``Ingredient`` class models the documents in the ``ingredients``
collection:

.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
:language: csharp
:dedent:
:start-after: start-ingredient-model
:end-before: end-ingredient-model

.. note:: Missing or Undefined Operands

If the operands you pass to any bitwise operator are of type `nullable <https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types>`__
``int`` or ``long`` and contain a missing or undefined value, the entire expression
evaluates to ``null``. If the operands are of type non-nullable ``int`` or
``long`` and contain a missing or undefined value, the {+driver-short+} will
throw an error.

$bitAnd
+++++++

The ``$bitAnd`` aggregation operator performs a bitwise AND operation on the given
arguments. You can use the ``$bitAnd`` operator by connecting two or more
clauses with a ``&`` character.

The following example shows how to create a ``$bitAnd`` stage by using LINQ. The
code retrieves the document in which the ``Name`` field has the
value ``"watermelon"``. It then performs a bitwise AND operation on the values of the
``IsAvailable`` and ``IsCheap`` fields in this document.

.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
:language: csharp
:dedent:
:start-after: start-bitAnd-example
:end-before: end-bitAnd-example

The preceding code returns ``1``, the result of the AND operation on the values
of the ``IsAvailable`` field (``1``) and the ``IsCheap`` field (``1``).

The following example performs the same bitwise AND operation on all
documents in the collection:

.. io-code-block::
:copyable: true

.. input:: /includes/fundamentals/code-examples/linq.cs
:language: csharp
:dedent:
:start-after: start-bitAnd-collection-example
:end-before: end-bitAnd-collection-example

.. output::
:language: json
:visible: false

1
0
0
1
0
null

The ``null`` result comes from the document where the ``Name`` field
has the value of ``"cheese"``. This document is missing an ``IsCheap`` field, so
the expression evaluates to ``null``.

$bitOr
++++++

The ``$bitOr`` aggregation operator performs a bitwise OR operation on the given
arguments. You can use the ``$bitOr`` operator by connecting two or more
clauses with a ``|`` character.

The following example shows how to create a ``$bitOr`` stage by using LINQ. The
code retrieves the document in which the ``Name`` field has the
value ``"onions"``. It then performs a bitwise OR operation on the values of the
``IsAvailable`` and ``IsCheap`` fields in this document.

.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
:language: csharp
:dedent:
:start-after: start-bitOr-example
:end-before: end-bitOr-example

The preceding code returns ``1``, the result of the OR operation on the values
of the ``IsAvailable`` field (``1``) and the ``IsCheap`` field (``0``).

$bitNot
+++++++

The ``$bitNot`` aggregation operator performs a bitwise NOT operation on the given
argument. You can use the ``$bitNot`` operator by preceding an
operand with a ``~`` character. ``$bitNot`` only takes one argument. The
following example shows how to create a ``$bitNot`` stage by using LINQ:

.. io-code-block::
:copyable: true

.. input:: /includes/fundamentals/code-examples/linq.cs
:language: csharp
:dedent:
:start-after: start-bitNot-example
:end-before: end-bitNot-example

.. output::
:language: json
:visible: false

-2
-1
-1
-2
-2
null

$bitXor
+++++++

The ``$bitXor`` aggregation operator performs a bitwise XOR operation on the given
arguments. You can use the ``$bitXor`` operator by connecting two or more
clauses with a ``^`` character.

The following example shows how to create a ``$bitXor`` stage by using LINQ. The
code retrieves the documents in which the ``Name`` field has
the value ``"watermelon"`` or ``"onions"``. It then performs a bitwise XOR
operation on the values of the ``IsAvailable`` and ``IsCheap`` fields in these
documents.

.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
:language: csharp
:dedent:
:start-after: start-bitXor-example
:end-before: end-bitXor-example

The result contains the following values:

.. code-block:: json

0
1


Unsupported Aggregation Stages
------------------------------

Expand Down
2 changes: 1 addition & 1 deletion source/includes/convention-pack-note.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. note::

The documents in the ``restaurants`` collection use the camel-case naming
The documents in the ``restaurants`` collection use the snake-case naming
convention. The examples in this guide use a ``ConventionPack``
to deserialize the fields in the collection into Pascal case and map them to
the properties in the ``Restaurant`` class.
Expand Down
57 changes: 56 additions & 1 deletion source/includes/fundamentals/code-examples/linq.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class Address
public string Building { get; set; }

[BsonElement("coord")]
public float[] Coordinates { get; set; }
public double[] Coordinates { get; set; }

public string Street { get; set; }

Expand Down Expand Up @@ -63,3 +63,58 @@ public class Review
}

// end-review-model

// start-ingredient-model

public class Ingredient
{
public int Id { get; set; }

public string Name { get; set; }

[BsonElement("is_available")]
public int? IsAvailable { get; set; }

[BsonElement("is_cheap")]
public int? IsCheap { get; set; }
}

// end-ingredient-model

// start-bitAnd-example

var query = queryableCollection
.Where(i => i.Name == "watermelon")
.Select(i => i.IsAvailable & i.IsCheap);

// end-bitAnd-example

// start-bitAnd-collection-example

var query = queryableCollection
.Select(i => i.IsAvailable & i.IsCheap);

// end-bitAnd-collection-example

// start-bitOr-example

var query = queryableCollection
.Where(i => i.Name == "onions")
.Select(i => i.IsAvailable | i.IsCheap);

// end-bitOr-example

// start-bitNot-example

var query = queryableCollection
.Select(i => ~i.IsCheap);

// end-bitNot-example

// start-bitXor-example

var query = queryableCollection
.Where(i => i.Name == "watermelon" || i.Name == "onions")
.Select(i => i.IsAvailable ^ i.IsCheap);

// end-bitXor-example

0 comments on commit a2e62bd

Please sign in to comment.