=========================
Execute Database Commands
=========================

.. default-domain:: mongodb

.. contents:: On this page
   :local:
   :backlinks: none
   :depth: 2
   :class: singlecol

Overview
--------

The |php-library| provides helper methods across the :phpclass:`Client
<MongoDB\Client>`, :phpclass:`Database <MongoDB\Database>`, and
:phpclass:`Collection <MongoDB\Collection>` classes for common
:manual:`database commands </reference/command>`. In addition, the
:phpmethod:`MongoDB\Database::command()` method may be used to run database
commands that do not have a helper method.

The :phpmethod:`MongoDB\Database::command()` method always returns a
:php:`MongoDB\Driver\Cursor <mongodb-driver-cursor>` object, since it must
support execution of commands that return single result documents *and* multiple
results via a command cursor.

Commands That Return a Single Result Document
---------------------------------------------

Most database commands return a single result document, which can be obtained by
converting the returned cursor to an array and accessing its first element. The
following example executes a :manual:`ping </reference/command/ping>` command
and prints its result document:

.. code-block:: php

   <?php

   $database = (new MongoDB\Client)->test;

   $cursor = $database->command(['ping' => 1]);

   var_dump($cursor->toArray()[0]);

The output would resemble:

.. code-block:: none

   object(MongoDB\Model\BSONDocument)#11 (1) {
     ["storage":"ArrayObject":private]=>
     array(1) {
       ["ok"]=>
       float(1)
     }
   }

Commands That Yield Multiple Results
------------------------------------

Some database commands return a cursor with multiple results. The following
example executes :manual:`listCollections </reference/command/listCollections>`,
which returns a cursor containing a result document for each collection in the
``test`` database, and iterates through the results using a ``foreach`` loop.
Note that this example is illustrative; applications would generally use
:phpmethod:`MongoDB\Database::listCollections()` in practice.

.. code-block:: php

   <?php

   $database = (new MongoDB\Client)->test;

   $cursor = $database->command(['listCollections' => 1]);

   foreach ($cursor as $collection) {
       echo $collection['name'], "\n";
   }

The output might resemble the following:

.. code-block:: none

   persons
   posts
   zips

.. note::

   At the *protocol* level, commands that yield multiple results via a cursor
   will return a single result document with the essential ingredients for
   constructing the cursor (i.e. the cursor's ID, namespace, and an optional
   first batch of results). If the :php:`MongoDB\Driver\Manager::executeCommand()
   <mongodb-driver-manager.executecommand>` method in the PHP driver detects
   such a response, it will construct an iterable command cursor and return it
   instead of the raw result document. If necessary, raw result documents can
   still be observed using `command monitoring
   <https://www.php.net/manual/en/mongodb.tutorial.apm.php>`_.

Specifying a Custom Read Preference
-----------------------------------

Write commands, such as :manual:`createUser </reference/command/createUser>`,
can only be executed on a writable server (e.g. :term:`primary` replica set
member). Command helper methods in the |php-library|, such as
:phpmethod:`MongoDB\Database::drop()`, know to apply their own :term:`read
preference` if necessary. However, the :phpmethod:`MongoDB\Database::command()`
method is a generic method and defaults to the read preference of the Database
object on which it is invoked. When necessary, the ``readPreference`` option may
be used to override the default read preference.

The following example connects to a cluster and specifies ``secondaryPreferred``
as the Client's default read preference. It then specifies a ``primary`` read
preference when executing the ``createUser`` command on the ``test`` database:

.. code-block:: php

   <?php

   $client = new MongoDB\Client(
      'mongodb+srv://cluster0.example.com',
      ['readPreference' => 'secondaryPreferred']
   );

   $client->test;

   $cursor = $db->command(
       [
           'createUser' => 'username',
           'pwd' => 'password',
           'roles' => ['readWrite'],
       ],
       [
           'readPreference' => new MongoDB\Driver\ReadPreference('primary'),
       ]
   );

   var_dump($cursor->toArray()[0]);

The output would then resemble:

.. code-block:: none

   object(MongoDB\Model\BSONDocument)#8 (1) {
     ["storage":"ArrayObject":private]=>
     array(1) {
       ["ok"]=>
       float(1)
     }
   }
