Skip to content

Commit 246b023

Browse files
committed
DOCSP-34044: Add bitwise operators to aggregation pipeline (#253)
* 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)
1 parent 97d1c30 commit 246b023

File tree

4 files changed

+240
-6
lines changed

4 files changed

+240
-6
lines changed

.github/workflows/vale-tdbx.yml

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ jobs:
1212
- name: checkout
1313
uses: actions/checkout@master
1414

15+
- name: Install docutils
16+
run: sudo apt-get install -y docutils
17+
1518
- id: files
1619
uses: masesgroup/retrieve-changed-files@v2
1720
with:

source/fundamentals/linq.txt

+180-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LINQ
77
.. contents:: On this page
88
:local:
99
:backlinks: none
10-
:depth: 2
10+
:depth: 3
1111
:class: singlecol
1212

1313

@@ -61,10 +61,11 @@ object that links to the collection. To create the object, use the ``AsQueryable
6161
as follows:
6262

6363
.. code-block:: csharp
64-
:emphasize-lines: 2
64+
:emphasize-lines: 3
6565

66-
var restaurantsCollection = restaurantsDatabase.GetCollection<Restaurant>("restaurants");
67-
var queryableCollection = restaurantsCollection.AsQueryable();
66+
var restaurantsDatabase = client.GetDatabase("sample_restaurants");
67+
var restaurantsCollection = restaurantsDatabase.GetCollection<Restaurant>("restaurants");
68+
var queryableCollection = restaurantsCollection.AsQueryable();
6869

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

572+
Bitwise Operators
573+
~~~~~~~~~~~~~~~~~
574+
575+
This section describes the :wikipedia:`bitwise operators <Bitwise_operation>`
576+
supported by the {+driver-short+} that you can use in an aggregation pipeline.
577+
You can use multiple bitwise operators in the same
578+
stage. The following guidelines apply when using bitwise operators:
579+
580+
- All operands must be of type ``int`` or ``long``.
581+
582+
- ``$bitAnd``, ``$bitOr``, and ``$bitXor`` take two or more operands. ``$bitNot`` takes one operand.
583+
584+
- Bitwise operations are evaluated from left to right.
585+
586+
The examples in this section use the following documents in a collection called
587+
``ingredients``:
588+
589+
.. code-block:: json
590+
591+
{ "_id" : 1, "name" : "watermelon", "is_available" : 1, "is_cheap" : 1 },
592+
{ "_id" : 2, "name" : "onions", "is_available" : 1, "is_cheap" : 0 },
593+
{ "_id" : 3, "name" : "eggs", "is_available" : 0, "is_cheap" : 0 },
594+
{ "_id" : 4, "name" : "potatoes", "is_available" : 1, "is_cheap" : 1 },
595+
{ "_id" : 5, "name" : "pasta", "is_available" : 0, "is_cheap" : 1 },
596+
{ "_id" : 6, "name" : "cheese", "is_available" : 1 }
597+
598+
The ``"is_available"`` field represents if an ingredient is available. If this
599+
field has a value of ``0``, the ingredient is not available. If it has a value
600+
of ``1``, the ingredient is available.
601+
602+
The ``"is_cheap"`` field represents if an ingredient is cheap. If this field has
603+
a value of ``0``, the ingredient is not cheap. If it has a value of ``1``, the
604+
ingredient is cheap.
605+
606+
The following ``Ingredient`` class models the documents in the ``ingredients``
607+
collection:
608+
609+
.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
610+
:language: csharp
611+
:dedent:
612+
:start-after: start-ingredient-model
613+
:end-before: end-ingredient-model
614+
615+
.. note:: Missing or Undefined Operands
616+
617+
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>`__
618+
``int`` or ``long`` and contain a missing or undefined value, the entire expression
619+
evaluates to ``null``. If the operands are of type non-nullable ``int`` or
620+
``long`` and contain a missing or undefined value, the {+driver-short+} will
621+
throw an error.
622+
623+
$bitAnd
624+
+++++++
625+
626+
The ``$bitAnd`` aggregation operator performs a bitwise AND operation on the given
627+
arguments. You can use the ``$bitAnd`` operator by connecting two or more
628+
clauses with a ``&`` character.
629+
630+
The following example shows how to create a ``$bitAnd`` stage by using LINQ. The
631+
code retrieves the document in which the ``Name`` field has the
632+
value ``"watermelon"``. It then performs a bitwise AND operation on the values of the
633+
``IsAvailable`` and ``IsCheap`` fields in this document.
634+
635+
.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
636+
:language: csharp
637+
:dedent:
638+
:start-after: start-bitAnd-example
639+
:end-before: end-bitAnd-example
640+
641+
The preceding code returns ``1``, the result of the AND operation on the values
642+
of the ``IsAvailable`` field (``1``) and the ``IsCheap`` field (``1``).
643+
644+
The following example performs the same bitwise AND operation on all
645+
documents in the collection:
646+
647+
.. io-code-block::
648+
:copyable: true
649+
650+
.. input:: /includes/fundamentals/code-examples/linq.cs
651+
:language: csharp
652+
:dedent:
653+
:start-after: start-bitAnd-collection-example
654+
:end-before: end-bitAnd-collection-example
655+
656+
.. output::
657+
:language: json
658+
:visible: false
659+
660+
1
661+
0
662+
0
663+
1
664+
0
665+
null
666+
667+
The ``null`` result comes from the document where the ``Name`` field
668+
has the value of ``"cheese"``. This document is missing an ``IsCheap`` field, so
669+
the expression evaluates to ``null``.
670+
671+
$bitOr
672+
++++++
673+
674+
The ``$bitOr`` aggregation operator performs a bitwise OR operation on the given
675+
arguments. You can use the ``$bitOr`` operator by connecting two or more
676+
clauses with a ``|`` character.
677+
678+
The following example shows how to create a ``$bitOr`` stage by using LINQ. The
679+
code retrieves the document in which the ``Name`` field has the
680+
value ``"onions"``. It then performs a bitwise OR operation on the values of the
681+
``IsAvailable`` and ``IsCheap`` fields in this document.
682+
683+
.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
684+
:language: csharp
685+
:dedent:
686+
:start-after: start-bitOr-example
687+
:end-before: end-bitOr-example
688+
689+
The preceding code returns ``1``, the result of the OR operation on the values
690+
of the ``IsAvailable`` field (``1``) and the ``IsCheap`` field (``0``).
691+
692+
$bitNot
693+
+++++++
694+
695+
The ``$bitNot`` aggregation operator performs a bitwise NOT operation on the given
696+
argument. You can use the ``$bitNot`` operator by preceding an
697+
operand with a ``~`` character. ``$bitNot`` only takes one argument. The
698+
following example shows how to create a ``$bitNot`` stage by using LINQ:
699+
700+
.. io-code-block::
701+
:copyable: true
702+
703+
.. input:: /includes/fundamentals/code-examples/linq.cs
704+
:language: csharp
705+
:dedent:
706+
:start-after: start-bitNot-example
707+
:end-before: end-bitNot-example
708+
709+
.. output::
710+
:language: json
711+
:visible: false
712+
713+
-2
714+
-1
715+
-1
716+
-2
717+
-2
718+
null
719+
720+
$bitXor
721+
+++++++
722+
723+
The ``$bitXor`` aggregation operator performs a bitwise XOR operation on the given
724+
arguments. You can use the ``$bitXor`` operator by connecting two or more
725+
clauses with a ``^`` character.
726+
727+
The following example shows how to create a ``$bitXor`` stage by using LINQ. The
728+
code retrieves the documents in which the ``Name`` field has
729+
the value ``"watermelon"`` or ``"onions"``. It then performs a bitwise XOR
730+
operation on the values of the ``IsAvailable`` and ``IsCheap`` fields in these
731+
documents.
732+
733+
.. literalinclude:: /includes/fundamentals/code-examples/linq.cs
734+
:language: csharp
735+
:dedent:
736+
:start-after: start-bitXor-example
737+
:end-before: end-bitXor-example
738+
739+
The result contains the following values:
740+
741+
.. code-block:: json
742+
743+
0
744+
1
745+
746+
571747
Unsupported Aggregation Stages
572748
------------------------------
573749

source/includes/convention-pack-note.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.. note::
22

3-
The documents in the ``restaurants`` collection use the camel-case naming
3+
The documents in the ``restaurants`` collection use the snake-case naming
44
convention. The examples in this guide use a ``ConventionPack``
55
to deserialize the fields in the collection into Pascal case and map them to
66
the properties in the ``Restaurant`` class.

source/includes/fundamentals/code-examples/linq.cs

+56-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class Address
2626
public string Building { get; set; }
2727

2828
[BsonElement("coord")]
29-
public float[] Coordinates { get; set; }
29+
public double[] Coordinates { get; set; }
3030

3131
public string Street { get; set; }
3232

@@ -63,3 +63,58 @@ public class Review
6363
}
6464

6565
// end-review-model
66+
67+
// start-ingredient-model
68+
69+
public class Ingredient
70+
{
71+
public int Id { get; set; }
72+
73+
public string Name { get; set; }
74+
75+
[BsonElement("is_available")]
76+
public int? IsAvailable { get; set; }
77+
78+
[BsonElement("is_cheap")]
79+
public int? IsCheap { get; set; }
80+
}
81+
82+
// end-ingredient-model
83+
84+
// start-bitAnd-example
85+
86+
var query = queryableCollection
87+
.Where(i => i.Name == "watermelon")
88+
.Select(i => i.IsAvailable & i.IsCheap);
89+
90+
// end-bitAnd-example
91+
92+
// start-bitAnd-collection-example
93+
94+
var query = queryableCollection
95+
.Select(i => i.IsAvailable & i.IsCheap);
96+
97+
// end-bitAnd-collection-example
98+
99+
// start-bitOr-example
100+
101+
var query = queryableCollection
102+
.Where(i => i.Name == "onions")
103+
.Select(i => i.IsAvailable | i.IsCheap);
104+
105+
// end-bitOr-example
106+
107+
// start-bitNot-example
108+
109+
var query = queryableCollection
110+
.Select(i => ~i.IsCheap);
111+
112+
// end-bitNot-example
113+
114+
// start-bitXor-example
115+
116+
var query = queryableCollection
117+
.Where(i => i.Name == "watermelon" || i.Name == "onions")
118+
.Select(i => i.IsAvailable ^ i.IsCheap);
119+
120+
// end-bitXor-example

0 commit comments

Comments
 (0)