Skip to content

Commit e45154a

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 edd0fe3 commit e45154a

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
@@ -587,6 +588,181 @@ in the Atlas manual. For more examples about running Atlas Vector Search queries
587588
{+driver-short+}, see :atlas:`Run Vector Search Queries </atlas-vector-search/vector-search-stage/>`
588589
in the Atlas manual and select :guilabel:`C#` from the language dropdown.
589590

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

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)