Skip to content

Commit 228cbb1

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 cdbc7e0 commit 228cbb1

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
.. facet::
@@ -68,10 +68,11 @@ object that links to the collection. To create the object, use the ``AsQueryable
6868
as follows:
6969

7070
.. code-block:: csharp
71-
:emphasize-lines: 2
71+
:emphasize-lines: 3
7272

73-
var restaurantsCollection = restaurantsDatabase.GetCollection<Restaurant>("restaurants");
74-
var queryableCollection = restaurantsCollection.AsQueryable();
73+
var restaurantsDatabase = client.GetDatabase("sample_restaurants");
74+
var restaurantsCollection = restaurantsDatabase.GetCollection<Restaurant>("restaurants");
75+
var queryableCollection = restaurantsCollection.AsQueryable();
7576

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

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

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)