diff --git a/config/redirects b/config/redirects index dc901280d09..b9980862721 100644 --- a/config/redirects +++ b/config/redirects @@ -1793,6 +1793,10 @@ raw: /manual/core/wildcard -> ${base}/manual/core/index-wildcard/ [v3.6-v4.4]: /${version}/reference/versioned-api/ -> ${base}/${version}/reference/ +[v3.6-v4.4]: /${version}/reference/operator/aggregation/getField/ -> ${base}/${version}/reference/operator/aggregation/ + +[v3.6-v4.4]: /${version}/reference/operator/aggregation/setField/ -> ${base}/${version}/reference/operator/aggregation/ + # # Redirects for 5.0 and greater (if pages are removed in 4.4 that used to exist in earlier versions) # diff --git a/source/includes/extracts-agg-operators.yaml b/source/includes/extracts-agg-operators.yaml index 752f1370303..0d61f4fa2b2 100644 --- a/source/includes/extracts-agg-operators.yaml +++ b/source/includes/extracts-agg-operators.yaml @@ -519,6 +519,15 @@ content: | * - Name - Description + * - :expression:`$getField` + + - Returns the value of a specified field from a document. + You can use :expression:`$getField` to retrieve the value of + fields with names that contain periods (``.``) or start + with dollar signs (``$``). + + .. versionadded:: 5.0 + * - :expression:`$rand` - Returns a random float between 0 and 1 @@ -553,6 +562,15 @@ content: | .. versionadded:: 3.6 + * - :expression:`$setField` + + - Adds, updates, or removes a specified field in a document. You + can use :expression:`$setField` to add, update, + or remove fields with names that contain periods (``.``) or + start with dollar signs (``$``). + + .. versionadded:: 5.0 + --- ref: agg-operators-set content: | @@ -818,7 +836,8 @@ content: | - Return a value without parsing. Use for values that the aggregation pipeline may interpret as an expression. For example, use a :expression:`$literal` expression to a string - that starts with a ``$`` to avoid parsing as a field path. + that starts with a dollar sign (``$``) to avoid parsing as a + field path. --- ref: agg-operators-custom-aggregation diff --git a/source/meta/aggregation-quick-reference.txt b/source/meta/aggregation-quick-reference.txt index 371c17c234f..0192dba3084 100644 --- a/source/meta/aggregation-quick-reference.txt +++ b/source/meta/aggregation-quick-reference.txt @@ -378,6 +378,7 @@ Index of Expression Operators - :group:`$first` (accumulator) - :expression:`$floor` - :expression:`$function` + - :expression:`$getField` - :expression:`$gt` - :expression:`$gte` - :expression:`$hour` @@ -432,6 +433,7 @@ Index of Expression Operators - :expression:`$second` - :expression:`$setDifference` - :expression:`$setEquals` + - :expression:`$setField` - :expression:`$setIntersection` - :expression:`$setIsSubset` - :expression:`$setUnion` diff --git a/source/reference/operator/aggregation.txt b/source/reference/operator/aggregation.txt index 4eb4abfe772..53897a988b3 100644 --- a/source/reference/operator/aggregation.txt +++ b/source/reference/operator/aggregation.txt @@ -493,6 +493,15 @@ Alphabetical Listing of Expression Operators .. versionadded:: 4.4 + * - :expression:`$getField` + + - Returns the value of a specified field from a document. + You can use :expression:`$getField` to retrieve the value of + fields with names that contain periods (``.``) or start + with dollar signs (``$``). + + .. versionadded: 5.0 + * - :expression:`$gt` - Returns ``true`` if the first value is @@ -861,8 +870,16 @@ Alphabetical Listing of Expression Operators - Returns ``true`` if the input sets have the same distinct elements. Accepts two or more argument expressions. - + * - :expression:`$setField` + + - Adds, updates, or removes a specified field in a document. + You can use :expression:`$setField` to add, update, + or remove fields with names that contain periods (``.``) or + start with dollar signs (``$``). + + .. versionadded:: 5.0 + * - :expression:`$setIntersection` - Returns a set with elements that appear in *all* of the input sets. @@ -1158,6 +1175,7 @@ Alphabetical Listing of Expression Operators /reference/operator/aggregation/first-array-element /reference/operator/aggregation/floor /reference/operator/aggregation/function + /reference/operator/aggregation/getField /reference/operator/aggregation/gt /reference/operator/aggregation/gte /reference/operator/aggregation/hour @@ -1215,6 +1233,7 @@ Alphabetical Listing of Expression Operators /reference/operator/aggregation/second /reference/operator/aggregation/setDifference /reference/operator/aggregation/setEquals + /reference/operator/aggregation/setField /reference/operator/aggregation/setIntersection /reference/operator/aggregation/setIsSubset /reference/operator/aggregation/setUnion diff --git a/source/reference/operator/aggregation/getField.txt b/source/reference/operator/aggregation/getField.txt new file mode 100644 index 00000000000..d4692d620b2 --- /dev/null +++ b/source/reference/operator/aggregation/getField.txt @@ -0,0 +1,188 @@ +======================= +$getField (aggregation) +======================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. expression:: $getField + + .. versionadded:: 5.0 + + Returns the value of a specified field from a document. If you + don't specify an object, :expression:`$getField` returns the value of + the field from :variable:`$$CURRENT `. + + You can use :expression:`$getField` to retrieve the value of fields + with names that contain periods (``.``) or start with dollar signs + (``$``). + + .. tip:: + + Use :expression:`$setField` to add or update fields with names + that contain dollar signs (``$``) or periods (``.``). + +Syntax +------ + +:expression:`$getField` has the following syntax: + +.. code-block:: javascript + + { + $getField: { + field: , + input: + } + } + +.. list-table:: + :header-rows: 1 + :widths: 20 20 80 + + * - Field + - Type + - Description + + * - ``field`` + - String + - Field in the ``input`` object for which you want to return a + value. ``field`` can be any valid :ref:`expression + ` that resolves to a string + constant. + + If ``field`` begins with a dollar sign (``$``), place the field + name inside of a :expression:`$literal` expression to return its + value. + + * - ``input`` + - Object + + *Default*: :variable:`$$CURRENT ` + + A valid :ref:`expression ` that + contains the ``field`` for which you want to return a value. + ``input`` must resolve to an object, ``missing``, + ``null``, or ``undefined``. If omitted, defaults + to the document currently being processed in the pipeline + (:variable:`$$CURRENT `). + +:expression:`$getField` has the following shorthand syntax for +retrieving field values from :variable:`$$CURRENT `: + +.. code-block:: javascript + + { + $getField: + } + +For this syntax, the argument is equivalent to the value of ``field`` +described above. + +Behavior +-------- + +- If ``field`` resolves to anything other than a string constant, + :expression:`$getField` returns an error. + +- If the ``field`` that you specify is not present in the ``input`` + object, or in :variable:`$$CURRENT ` if you don't specify an + ``input`` object, :expression:`$getField` returns ``missing``. + +- If ``input`` evaluates to ``missing``, ``undefined``, or ``null``, + :expression:`$getField` returns ``null``. + +- If ``input`` evaluates to anything other than an object, ``missing``, + ``undefined``, or ``null``, :expression:`$getField` returns an error. + +- :expression:`$getField` doesn't implicitly traverse objects or arrays. + For example, :expression:`$getField` evaluates a ``field`` value of + ``a.b.c`` as a top-level field ``a.b.c`` instead of a nested field + ``{ a: { b: { c: } } }``. + +Examples +-------- + +Query Fields that Contain Periods (``.``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { "_id" : 1, "item" : "sweatshirt", "price.usd": 45.99, qty: 300 } + { "_id" : 2, "item" : "winter coat", "price.usd": 499.99, qty: 200 } + { "_id" : 3, "item" : "sun dress", "price.usd": 199.99, qty: 250 } + { "_id" : 4, "item" : "leather boots", "price.usd": 249.99, qty: 300 } + { "_id" : 5, "item" : "bow tie", "price.usd": 9.99, qty: 180 } + +The following operation uses the :expression:`$getField` and +:expression:`$gt` operators to find which products have a ``price.usd`` +greater than ``200``: + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $match: + { $expr: + { $gt: [ { $getField: "price.usd" }, 200 ] } + } + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 2, item: 'winter coat', qty: 200, 'price.usd': 499.99 }, + { _id: 4, item: 'leather boots', qty: 300, 'price.usd': 249.99 } + ] + +Query Fields that Start with a Dollar Sign (``$``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { "_id" : 1, "item" : "sweatshirt", "$price": 45.99, qty: 300 } + { "_id" : 2, "item" : "winter coat", "$price": 499.99, qty: 200 } + { "_id" : 3, "item" : "sun dress", "$price": 199.99, qty: 250 } + { "_id" : 4, "item" : "leather boots", "$price": 249.99, qty: 300 } + { "_id" : 5, "item" : "bow tie", "$price": 9.99, qty: 180 } + +The following operation uses the :expression:`$getField`, +:expression:`$gt`, and :expression:`$literal` operators to find which +products have a ``$price`` greater than ``200``: + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $match: + { $expr: + { $gt: [ { $getField: {$literal: "$price" } }, 200 ] } + } + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 2, item: 'winter coat', qty: 200, '$price': 499.99 }, + { _id: 4, item: 'leather boots', qty: 300, '$price': 249.99 } + ] diff --git a/source/reference/operator/aggregation/setField.txt b/source/reference/operator/aggregation/setField.txt new file mode 100644 index 00000000000..6995e7ced04 --- /dev/null +++ b/source/reference/operator/aggregation/setField.txt @@ -0,0 +1,387 @@ +======================= +$setField (aggregation) +======================= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. expression:: $setField + + .. versionadded:: 5.0 + + Adds, updates, or removes a specified field in a document. + + You can use :expression:`$setField` to add, update, or remove fields + with names that contain periods (``.``) or start with dollar + signs (``$``). + + .. tip:: + + Use :expression:`$getField` to retrieve the values of fields that + contain dollar signs (``$``) or periods (``.``) that you add or + update with :expression:`$setField`. + +Syntax +------ + +:expression:`$setField` has the following syntax: + +.. code-block:: javascript + + { + $setField: { + field: , + input: , + value: + } + } + +You must provide the following fields: + +.. list-table:: + :header-rows: 1 + :widths: 20 20 80 + + * - Field + - Type + - Description + + * - ``field`` + - String + - Field in the ``input`` object that you want to add, update, or + remove. ``field`` can be any valid :ref:`expression + ` that resolves to a string + constant. + + * - ``input`` + - Object + - Document that contains the ``field`` that you want to add or + update. ``input`` must resolve to an object, ``missing``, + ``null``, or ``undefined``. + + * - ``value`` + - Expression + - The value that you want to assign to ``field``. ``value`` can be + any valid :ref:`expression `. + + Set to :variable:`$$REMOVE ` to remove ``field`` from the + ``input`` document. + +Behavior +-------- + +- If ``input`` evaluates to ``missing``, ``undefined``, or ``null``, + :expression:`$setField` returns ``null`` and does not update ``input``. + +- If ``input`` evaluates to anything other than an object, ``missing``, + ``undefined``, or ``null``, :expression:`$setField` returns an error. + +- If ``field`` resolves to anything other than a string constant, + :expression:`$setField` returns an error. + +- If ``field`` doesn't exist in ``input``, :expression:`$setField` + adds it. + +- :expression:`$setField` doesn't implicitly traverse objects or arrays. + For example, :expression:`$setField` evaluates a ``field`` value of + ``a.b.c`` as a top-level field ``a.b.c`` instead of a nested field + ``{ a: { b: { c: } } }``. + +Examples +-------- + +Add Fields that Contain Periods (``.``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { "_id" : 1, "item" : "sweatshirt", price: 45.99, qty: 300 } + { "_id" : 2, "item" : "winter coat", price: 499.99, qty: 200 } + { "_id" : 3, "item" : "sun dress", price: 199.99, qty: 250 } + { "_id" : 4, "item" : "leather boots", price: 249.99, qty: 300 } + { "_id" : 5, "item" : "bow tie", price: 9.99, qty: 180 } + +The following operation uses the :pipeline:`$replaceWith` pipeline stage +and the :expression:`$setField` operator to add a new field to each +document, ``price.usd``. The value of ``price.usd`` will equal the +value of ``price`` in each document. Finally, the operation uses the +:pipeline:`$unset` pipeline stage to remove the ``price`` field. + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $replaceWith: + { + $setField: + { + field: "price.usd", + input: "$$ROOT", + value: "$price" + } + } + }, + { + $unset: "price" + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 1, item: 'sweatshirt', qty: 300, 'price.usd': 45.99 }, + { _id: 2, item: 'winter coat', qty: 200, 'price.usd': 499.99 }, + { _id: 3, item: 'sun dress', qty: 250, 'price.usd': 199.99 }, + { _id: 4, item: 'leather boots', qty: 300, 'price.usd': 249.99 }, + { _id: 5, item: 'bow tie', qty: 180, 'price.usd': 9.99 } + ] + +Add Fields that Start with a Dollar Sign (``$``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { "_id" : 1, "item" : "sweatshirt", price: 45.99, qty: 300 } + { "_id" : 2, "item" : "winter coat", price: 499.99, qty: 200 } + { "_id" : 3, "item" : "sun dress", price: 199.99, qty: 250 } + { "_id" : 4, "item" : "leather boots", price: 249.99, qty: 300 } + { "_id" : 5, "item" : "bow tie", price: 9.99, qty: 180 } + +The following operation uses the :pipeline:`$replaceWith` pipeline stage +and the :expression:`$setField` and :expression:`$literal` operators to +add a new field to each document, ``$price``. The value of ``$price`` +will equal the value of ``price`` in each document. Finally, the +operation uses the :pipeline:`$unset` pipeline stage to remove the +``price`` field. + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $replaceWith: + { + $setField: + { + field: {$literal: "$price"}, + input: "$$ROOT", + value: "$price" + } + } + }, + { + $unset: "price" + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 1, item: 'sweatshirt', qty: 300, '$price': 45.99 }, + { _id: 2, item: 'winter coat', qty: 200, '$price': 499.99 }, + { _id: 3, item: 'sun dress', qty: 250, '$price': 199.99 }, + { _id: 4, item: 'leather boots', qty: 300, '$price': 249.99 }, + { _id: 5, item: 'bow tie', qty: 180, '$price': 9.99 } + ] + +Update Fields that Contain Periods (``.``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { _id: 1, item: 'sweatshirt', qty: 300, 'price.usd': 45.99 }, + { _id: 2, item: 'winter coat', qty: 200, 'price.usd': 499.99 }, + { _id: 3, item: 'sun dress', qty: 250, 'price.usd': 199.99 }, + { _id: 4, item: 'leather boots', qty: 300, 'price.usd': 249.99 }, + { _id: 5, item: 'bow tie', qty: 180, 'price.usd': 9.99 } + +The following operation uses the :pipeline:`$match` pipeline stage to +find a specific document and the :pipeline:`$replaceWith` pipeline stage +and the :expression:`$setField` operator to update the ``price.usd`` +field in the matching document: + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $match: { _id: 1 } + }, + { + $replaceWith: + { + $setField: + { + field: "price.usd", + input: "$$ROOT", + value: 49.99 + } + } + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 1, item: 'sweatshirt', qty: 300, 'price.usd': 49.99 } + ] + +Update Fields that Start with a Dollar Sign (``$``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { _id: 1, item: 'sweatshirt', qty: 300, '$price': 45.99 }, + { _id: 2, item: 'winter coat', qty: 200, '$price': 499.99 }, + { _id: 3, item: 'sun dress', qty: 250, '$price': 199.99 }, + { _id: 4, item: 'leather boots', qty: 300, '$price': 249.99 }, + { _id: 5, item: 'bow tie', qty: 180, '$price': 9.99 } + +The following operation uses the :pipeline:`$match` pipeline stage to +find a specific document and the :pipeline:`$replaceWith` pipeline stage +and the :expression:`$setField` and :expression:`$literal` operators to +update the ``$price`` field in the matching document: + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $match: { _id: 1 } + }, + { + $replaceWith: + { + $setField: + { + field: {$literal: "$price"}, + input: "$$ROOT", + value: 49.99 + } + } + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 1, item: 'sweatshirt', qty: 300, '$price': 49.99 } + ] + +Remove Fields that Contain Periods (``.``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { _id: 1, item: 'sweatshirt', qty: 300, 'price.usd': 45.99 }, + { _id: 2, item: 'winter coat', qty: 200, 'price.usd': 499.99 }, + { _id: 3, item: 'sun dress', qty: 250, 'price.usd': 199.99 }, + { _id: 4, item: 'leather boots', qty: 300, 'price.usd': 249.99 }, + { _id: 5, item: 'bow tie', qty: 180, 'price.usd': 9.99 } + +The following operation uses the :pipeline:`$replaceWith` pipeline stage +and the :expression:`$setField` operator and :variable:`$$REMOVE +` to remove the ``price.usd`` field from each document: + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $replaceWith: + { + $setField: + { + field: "price.usd", + input: "$$ROOT", + value: "$$REMOVE" + } + } + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 1, item: 'sweatshirt', qty: 300 }, + { _id: 2, item: 'winter coat', qty: 200 }, + { _id: 3, item: 'sun dress', qty: 250 }, + { _id: 4, item: 'leather boots', qty: 300 }, + { _id: 5, item: 'bow tie', qty: 180 } + ] + +Remove Fields that Start with a Dollar Sign (``$``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider an ``inventory`` collection with the following documents: + +.. code-block:: javascript + + { _id: 1, item: 'sweatshirt', qty: 300, '$price': 45.99 }, + { _id: 2, item: 'winter coat', qty: 200, '$price': 499.99 }, + { _id: 3, item: 'sun dress', qty: 250, '$price': 199.99 }, + { _id: 4, item: 'leather boots', qty: 300, '$price': 249.99 }, + { _id: 5, item: 'bow tie', qty: 180, '$price': 9.99 } + +The following operation uses the :pipeline:`$replaceWith` pipeline +stage, the :expression:`$setField` and :expression:`$literal` operators, +and :variable:`$$REMOVE ` to remove the ``$price`` field +from each document: + +.. code-block:: javascript + + db.inventory.aggregate([ + { + $replaceWith: + { + $setField: + { + field: {$literal: "$price"}, + input: "$$ROOT", + value: "$$REMOVE" + } + } + } + ]) + +The operation returns the following results: + +.. code-block:: javascript + :copyable: false + + [ + { _id: 1, item: 'sweatshirt', qty: 300 }, + { _id: 2, item: 'winter coat', qty: 200 }, + { _id: 3, item: 'sun dress', qty: 250 }, + { _id: 4, item: 'leather boots', qty: 300 }, + { _id: 5, item: 'bow tie', qty: 180 } + ] diff --git a/source/release-notes/5.0.txt b/source/release-notes/5.0.txt index 882b81c82f4..934915d9376 100644 --- a/source/release-notes/5.0.txt +++ b/source/release-notes/5.0.txt @@ -65,10 +65,22 @@ MongoDB 5.0 introduces the following aggregation operators: - Decrements a :doc:`Date ` object by a specified number of time units. + * - :expression:`$getField` + - Returns the value of a specified field from a document. + You can use :expression:`$getField` to retrieve the value of + fields with names that contain periods (``.``) or start + with dollar signs (``$``). + * - :expression:`$sampleRate` - Adds the :expression:`$sampleRate` method to probabilistically select documents from a pipeline at a given rate. + * - :expression:`$setField` + - Adds, updates, or removes a specified field in a document. + You can use :expression:`$setField` to add, update, + or remove fields with names that contain periods (``.``) or + start with dollar signs (``$``). + * - :expression:`$rand` - The :expression:`$rand` method generates a random float value between 0 and 1 each time it is called. The new