.. Licensed under the Apache License, Version 2.0 (the "License"); you may not
.. use this file except in compliance with the License. You may obtain a copy of
.. the License at
..
..   http://www.apache.org/licenses/LICENSE-2.0
..
.. Unless required by applicable law or agreed to in writing, software
.. distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
.. WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
.. License for the specific language governing permissions and limitations under
.. the License.

.. _api/db/changes:

================
``/db/_changes``
================

.. http:get:: /{db}/_changes
    :synopsis: Returns changes for the given database

    Returns a sorted list of changes made to documents in the database, in time
    order of application, can be obtained from the database's ``_changes``
    resource. Only the most recent change for a given document is guaranteed to
    be provided, for example if a document has had fields added, and then
    deleted, an API client checking for changes will not necessarily receive
    the intermediate state of added documents.

    This can be used to listen for update and modifications to the database for
    post processing or synchronization, and for practical purposes,
    a continuously connected ``_changes`` feed is a reasonable approach for
    generating a real-time log for most applications.

    :param db: Database name
    :<header Accept: - :mimetype:`application/json`
                     - :mimetype:`text/event-stream`
                     - :mimetype:`text/plain`
    :<header Last-Event-ID: ID of the last events received by the server on a
        previous connection. Overrides `since` query parameter.
    :query array doc_ids: List of document IDs to filter the changes feed as
        valid JSON array. Used with :ref:`_doc_ids <changes/filter/doc_ids>`
        filter. Since `length of URL is limited`_, it is better to use
        :post:`/{db}/_changes` instead.
    :query boolean conflicts: Includes `conflicts` information in response.
        Ignored if `include_docs` isn't ``true``. Default is ``false``.
    :query boolean descending: Return the change results in descending sequence
        order (most recent change first). Default is ``false``.
    :query string feed: - **normal** Specifies :ref:`Normal Polling Mode
                          <changes/normal>`. All past changes are returned
                          immediately. *Default.*
                        - **longpoll** Specifies :ref:`Long Polling Mode
                          <changes/longpoll>`. Waits until at least one change
                          has occurred, sends the change, then closes the
                          connection. Most commonly used in conjunction with
                          ``since=now``, to wait for the next change.
                        - **continuous** Sets :ref:`Continuous Mode
                          <changes/continuous>`. Sends a line of JSON per
                          event. Keeps the socket open until ``timeout``.
                        - **eventsource** Sets :ref:`Event Source Mode
                          <changes/eventsource>`. Works the same as Continuous
                          Mode, but sends the events in `EventSource
                          <http://dev.w3.org/html5/eventsource/>`_ format.
    :query string filter: Reference to a :ref:`filter function <filterfun>`
        from a design document that will filter whole stream emitting only
        filtered events. See the section `Change Notifications in the book
        CouchDB The Definitive Guide`_ for more information.
    :query number heartbeat: Period in *milliseconds* after which an empty
        line is sent in the results. Only applicable for :ref:`longpoll
        <changes/longpoll>`, :ref:`continuous <changes/continuous>`, and
        :ref:`eventsource <changes/eventsource>` feeds. Overrides any timeout
        to keep the feed alive indefinitely. Default is ``60000``. May be
        ``true`` to use default value.
    :query boolean include_docs: Include the associated document with each
        result. If there are conflicts, only the winning revision is returned.
        Default is ``false``.
    :query boolean attachments: Include the Base64-encoded content of
        :ref:`attachments <api/doc/attachments>` in the documents that
        are included if `include_docs` is ``true``. Ignored if `include_docs`
        isn't ``true``. Default is ``false``.
    :query boolean att_encoding_info: Include encoding information in attachment
        stubs if `include_docs` is ``true`` and the particular attachment is
        compressed. Ignored if `include_docs` isn't ``true``.
        Default is ``false``.
    :query number last-event-id: Alias of `Last-Event-ID` header.
    :query number limit: Limit number of result rows to the specified value
        (note that using ``0`` here has the same effect as ``1``).
    :query since: Start the results from the change immediately after the given
        update sequence. Can be valid update sequence or ``now`` value.
        Default is ``0``.
    :query string style: Specifies how many revisions are returned in
        the changes array. The default, ``main_only``, will only return
        the current "winning" revision; ``all_docs`` will return all leaf
        revisions (including conflicts and deleted former conflicts).
    :query number timeout: Maximum period in *milliseconds* to wait for a change
        before the response is sent, even if there are no results.
        Only applicable for :ref:`longpoll <changes/longpoll>` or
        :ref:`continuous <changes/continuous>` feeds.
        Default value is specified by :config:option:`httpd/changes_timeout`
        configuration option. Note that ``60000`` value is also the default
        maximum timeout to prevent undetected dead connections.
    :query string view: Allows to use view functions as filters. Documents
        counted as "passed" for view filter in case if map function emits
        at least one record for them.
        See :ref:`changes/filter/view` for more info.
    :query number seq_interval: When fetching changes in a batch, setting the
        *seq_interval* parameter tells CouchDB to only calculate the update seq
        with every Nth result returned. By setting **seq_interval=<batch size>**
        , where ``<batch size>`` is the number of results requested per batch,
        load can be reduced on the source CouchDB database; computing the seq
        value across many shards (esp. in highly-sharded databases) is expensive
        in a heavily loaded CouchDB cluster.
    :>header Cache-Control: ``no-cache`` if changes feed is
        :ref:`eventsource <changes/eventsource>`
    :>header Content-Type: - :mimetype:`application/json`
                           - :mimetype:`text/event-stream`
                           - :mimetype:`text/plain; charset=utf-8`
    :>header ETag: Response hash is changes feed is `normal`
    :>header Transfer-Encoding: ``chunked``
    :>json json last_seq: Last change update sequence
    :>json number pending: Count of remaining items in the feed
    :>json array results: Changes made to a database
    :code 200: Request completed successfully
    :code 400: Bad request

    The ``results`` field of database changes:

    :json array changes: List of document's leaves with single field ``rev``.
    :json string id: Document ID.
    :json json seq: Update sequence.
    :json bool deleted: ``true`` if the document is deleted.

    **Request**:

    .. code-block:: http

        GET /db/_changes?style=all_docs HTTP/1.1
        Accept: application/json
        Host: localhost:5984

    **Response**:

    .. code-block:: http

        HTTP/1.1 200 OK
        Cache-Control: must-revalidate
        Content-Type: application/json
        Date: Mon, 12 Aug 2013 00:54:58 GMT
        ETag: "6ASLEKEMSRABT0O5XY9UPO9Z"
        Server: CouchDB (Erlang/OTP)
        Transfer-Encoding: chunked

        {
            "last_seq": "5-g1AAAAIreJyVkEsKwjAURZ-toI5cgq5A0sQ0OrI70XyppcaRY92J7kR3ojupaSPUUgotgRd4yTlwbw4A0zRUMLdnpaMkwmyF3Ily9xBwEIuiKLI05KOTW0wkV4rruP29UyGWbordzwKVxWBNOGMKZhertDlarbr5pOT3DV4gudUC9-MPJX9tpEAYx4TQASns2E24ucuJ7rXJSL1BbEgf3vTwpmedCZkYa7Pulck7Xt7x_usFU2aIHOD4eEfVTVA5KMGUkqhNZV-8_o5i",
            "pending": 0,
            "results": [
                {
                    "changes": [
                        {
                            "rev": "2-7051cbe5c8faecd085a3fa619e6e6337"
                        }
                    ],
                    "id": "6478c2ae800dfc387396d14e1fc39626",
                    "seq": "3-g1AAAAG3eJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MSGXAqSVIAkkn2IFUZzIkMuUAee5pRqnGiuXkKA2dpXkpqWmZeagpu_Q4g_fGEbEkAqaqH2sIItsXAyMjM2NgUUwdOU_JYgCRDA5ACGjQfn30QlQsgKvcjfGaQZmaUmmZClM8gZhyAmHGfsG0PICrBPmQC22ZqbGRqamyIqSsLAAArcXo"
                },
                {
                    "changes": [
                        {
                            "rev": "3-7379b9e515b161226c6559d90c4dc49f"
                        }
                    ],
                    "deleted": true,
                    "id": "5bbc9ca465f1b0fcd62362168a7c8831",
                    "seq": "4-g1AAAAHXeJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBMZc4EC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HqQ_kQG3qgSQqnoUtxoYGZkZG5uS4NY8FiDJ0ACkgAbNx2cfROUCiMr9CJ8ZpJkZpaaZEOUziBkHIGbcJ2zbA4hKsA-ZwLaZGhuZmhobYurKAgCz33kh"
                },
                {
                    "changes": [
                        {
                            "rev": "6-460637e73a6288cb24d532bf91f32969"
                        },
                        {
                            "rev": "5-eeaa298781f60b7bcae0c91bdedd1b87"
                        }
                    ],
                    "id": "729eb57437745e506b333068fff665ae",
                    "seq": "5-g1AAAAIReJyVkE0OgjAQRkcwUVceQU9g-mOpruQm2tI2SLCuXOtN9CZ6E70JFmpCCCFCmkyTdt6bfJMDwDQNFcztWWkcY8JXyB2cu49AgFwURZGloRid3MMkEUoJHbXbOxVy6arc_SxQWQzRVHCuYHaxSpuj1aqbj0t-3-AlSrZakn78oeSvjRSIkIhSNiCFHbsKN3c50b02mURvEB-yD296eNOzzoRMRLRZ98rkHS_veGcC_nR-fGe1gaCaxihhjOI2lX0BhniHaA"
                }
            ]
        }

.. _length of URL is limited: http://stackoverflow.com/a/417184/965635

.. versionchanged:: 0.11.0 added ``include_docs`` parameter
.. versionchanged:: 1.2.0 added ``view`` parameter and special value `_view`
   for ``filter`` one
.. versionchanged:: 1.3.0 ``since`` parameter could take `now` value to start
   listen changes since current seq number.
.. versionchanged:: 1.3.0 ``eventsource`` feed type added.
.. versionchanged:: 1.4.0 Support ``Last-Event-ID`` header.
.. versionchanged:: 1.6.0 added ``attachments`` and ``att_encoding_info``
   parameters
.. versionchanged:: 2.0.0 update sequences can be any valid json object,
   added ``seq_interval``

.. note::
    If the specified replicas of the shards in any given since value are
    unavailable, alternative replicas are selected, and the last known
    checkpoint between them is used. If this happens, you might see changes
    again that you have previously seen. Therefore, an application making use
    of the `_changes` feed should be ‘idempotent’, that is, able to receive the
    same data multiple times, safely.

.. note::
    Cloudant Sync and PouchDB already optimize the replication process by
    setting ``seq_interval`` parameter to the number of results expected per
    batch. This parameter increases throughput by reducing latency between
    sequential requests in bulk document transfers. This has resulted in up to
    a 20% replication performance improvement in highly-sharded databases.

.. warning::
    Using the ``attachments`` parameter to include attachments in the changes
    feed is not recommended for large attachment sizes. Also note that the
    Base64-encoding that is used leads to a 33% overhead (i.e. one third) in
    transfer size for attachments.

.. warning::
    The results returned by `_changes` are partially ordered. In other words,
    the order is not guaranteed to be preserved for multiple calls.

.. http:post:: /{db}/_changes
    :synopsis: Returns changes for the given database for certain document IDs

    Requests the database changes feed in the same way as
    :get:`/{db}/_changes` does, but is widely used with
    ``?filter=_doc_ids`` query parameter and allows one to pass a larger list of
    document IDs to filter.

    **Request**:

    .. code-block:: http

        POST /recipes/_changes?filter=_doc_ids HTTP/1.1
        Accept: application/json
        Content-Length: 40
        Content-Type: application/json
        Host: localhost:5984

        {
            "doc_ids": [
                "SpaghettiWithMeatballs"
            ]
        }

    **Response**:

    .. code-block:: http

        HTTP/1.1 200 OK
        Cache-Control: must-revalidate
        Content-Type: application/json
        Date: Sat, 28 Sep 2013 07:23:09 GMT
        ETag: "ARIHFWL3I7PIS0SPVTFU6TLR2"
        Server: CouchDB (Erlang OTP)
        Transfer-Encoding: chunked

        {
            "last_seq": "5-g1AAAAIreJyVkEsKwjAURZ-toI5cgq5A0sQ0OrI70XyppcaRY92J7kR3ojupaSPUUgotgRd4yTlwbw4A0zRUMLdnpaMkwmyF3Ily9xBwEIuiKLI05KOTW0wkV4rruP29UyGWbordzwKVxWBNOGMKZhertDlarbr5pOT3DV4gudUC9-MPJX9tpEAYx4TQASns2E24ucuJ7rXJSL1BbEgf3vTwpmedCZkYa7Pulck7Xt7x_usFU2aIHOD4eEfVTVA5KMGUkqhNZV8_o5i",
            "pending": 0,
            "results": [
                {
                    "changes": [
                        {
                            "rev": "13-bcb9d6388b60fd1e960d9ec4e8e3f29e"
                        }
                    ],
                    "id": "SpaghettiWithMeatballs",
                    "seq":  "5-g1AAAAIReJyVkE0OgjAQRkcwUVceQU9g-mOpruQm2tI2SLCuXOtN9CZ6E70JFmpCCCFCmkyTdt6bfJMDwDQNFcztWWkcY8JXyB2cu49AgFwURZGloRid3MMkEUoJHbXbOxVy6arc_SxQWQzRVHCuYHaxSpuj1aqbj0t-3-AlSrZakn78oeSvjRSIkIhSNiCFHbsKN3c50b02mURvEB-yD296eNOzzoRMRLRZ98rkHS_veGcC_nR-fGe1gaCaxihhjOI2lX0BhniHaA"
                }
            ]
        }

.. _changes:

Changes Feeds
=============

.. _changes/normal:

Polling
-------

By default all changes are immediately returned within the JSON body::

    GET /somedatabase/_changes HTTP/1.1

.. code-block:: javascript

    {"results":[
    {"seq":"1-g1AAAAF9eJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P__7MSGXAqSVIAkkn2IFUZzIkMuUAee5pRqnGiuXkKA2dpXkpqWmZeagpu_Q4g_fGEbEkAqaqH2sIItsXAyMjM2NgUUwdOU_JYgCRDA5ACGjQfn30QlQsgKvcTVnkAovI-YZUPICpBvs0CAN1eY_c","id":"fresh","changes":[{"rev":"1-967a00dff5e02add41819138abb3284d"}]},
    {"seq":"3-g1AAAAG3eJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MSGXAqSVIAkkn2IFUZzIkMuUAee5pRqnGiuXkKA2dpXkpqWmZeagpu_Q4g_fGEbEkAqaqH2sIItsXAyMjM2NgUUwdOU_JYgCRDA5ACGjQfn30QlQsgKvcjfGaQZmaUmmZClM8gZhyAmHGfsG0PICrBPmQC22ZqbGRqamyIqSsLAAArcXo","id":"updated","changes":[{"rev":"2-7051cbe5c8faecd085a3fa619e6e6337CFCmkyTdt6bfJMDwDQNFcztWWkcY8JXyB2cu49AgFwURZGloRid3MMkEUoJHbXbOxVy6arc_SxQWQzRVHCuYHaxSpuj1aqbj0t-3-AlSrZakn78oeSvjRSIkIhSNiCFHbsKN3c50b02mURvEB-yD296eNOzzoRMRLRZ98rkHS_veGcC_nR-fGe1gaCaxihhjOI2lX0BhniHaA","id":"deleted","changes":[{"rev":"2-eec205a9d413992850a6e32678485900"}],"deleted":true}
    ],
    "last_seq":"5-g1AAAAIreJyVkEsKwjAURZ-toI5cgq5A0sQ0OrI70XyppcaRY92J7kR3ojupaSPUUgotgRd4yTlwbw4A0zRUMLdnpaMkwmyF3Ily9xBwEIuiKLI05KOTW0wkV4rruP29UyGWbordzwKVxWBNOGMKZhertDlarbr5pOT3DV4gudUC9-MPJX9tpEAYx4TQASns2E24ucuJ7rXJSL1BbEgf3vTwpmedCZkYa7Pulck7Xt7x_usFU2aIHOD4eEfVTVA5KMGUkqhNZV-8_o5i",
    "pending": 0}

``results`` is the list of changes in sequential order. New and changed
documents only differ in the value of the rev; deleted documents include the
``"deleted": true`` attribute. (In the ``style=all_docs mode``, deleted applies
only to the current/winning revision. The other revisions listed might be
deleted even if there is no deleted property; you have to ``GET`` them
individually to make sure.)

``last_seq`` is the update sequence of the last update returned (Equivalent
to the last item in the results).

Sending a ``since`` param in the query string skips all changes up to and
including the given update sequence:

.. code-block:: http

    GET /somedatabase/_changes?since=4-g1AAAAHXeJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBMZc4EC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HqQ_kQG3qgSQqnoUtxoYGZkZG5uS4NY8FiDJ0ACkgAbNx2cfROUCiMr9CJ8ZpJkZpaaZEOUziBkHIGbcJ2zbA4hKsA-ZwLaZGhuZmhobYurKAgCz33kh HTTP/1.1

The return structure for ``normal`` and ``longpoll`` modes is a JSON
array of changes objects, and the last update sequence.

In the return format for ``continuous`` mode, the server sends a ``CRLF``
(carriage-return, linefeed) delimited line for each change. Each line
contains the `JSON object` described above.

You can also request the full contents of each document change (instead
of just the change notification) by using the ``include_docs`` parameter.

.. code-block:: javascript

    {
        "last_seq": "5-g1AAAAIreJyVkEsKwjAURZ-toI5cgq5A0sQ0OrI70XyppcaRY92J7kR3ojupaSPUUgotgRd4yTlwbw4A0zRUMLdnpaMkwmyF3Ily9xBwEIuiKLI05KOTW0wkV4rruP29UyGWbordzwKVxWBNOGMKZhertDlarbr5pOT3DV4gudUC9-MPJX9tpEAYx4TQASns2E24ucuJ7rXJSL1BbEgf3vTwpmedCZkYa7Pulck7Xt7x_usFU2aIHOD4eEfVTVA5KMGUkqhNZV-8_o5i",
        "pending": 0,
        "results": [
            {
                "changes": [
                    {
                        "rev": "2-eec205a9d413992850a6e32678485900"
                    }
                ],
                "deleted": true,
                "id": "deleted",
                "seq":  "5-g1AAAAIReJyVkE0OgjAQRkcwUVceQU9g-mOpruQm2tI2SLCuXOtN9CZ6E70JFmpCCCFCmkyTdt6bfJMDwDQNFcztWWkcY8JXyB2cu49AgFwURZGloRid3MMkEUoJHbXbOxVy6arc_SxQWQzRVHCuYHaxSpuj1aqbj0t-3-AlSrZakn78oeSvjRSIkIhSNiCFHbsKN3c50b02mURvEByD296eNOzzoRMRLRZ98rkHS_veGcC_nR-fGe1gaCaxihhjOI2lX0BhniHaA",
            }
        ]
    }

.. _changes/longpoll:

Long Polling
------------

The `longpoll` feed, probably most applicable for a browser, is a more
efficient form of polling that waits for a change to occur before the response
is sent. `longpoll` avoids the need to frequently poll CouchDB to discover
nothing has changed!

The request to the server will remain open until a change is made on the
database and is subsequently transferred, and then the connection will close.
This is low load for both server and client.

The response is basically the same JSON as is sent for the `normal` feed.

Because the wait for a change can be significant you can set a
timeout before the connection is automatically closed (the
``timeout`` argument). You can also set a heartbeat interval (using
the ``heartbeat`` query argument), which sends a newline to keep the
connection active.

.. _changes/continuous:

Continuous
----------

Continually polling the CouchDB server is not ideal - setting up new HTTP
connections just to tell the client that nothing happened puts unnecessary
strain on CouchDB.

A continuous feed stays open and connected to the database until explicitly
closed and changes are sent to the client as they happen, i.e. in near
real-time.

As with the `longpoll` feed type you can set both the timeout and heartbeat
intervals to ensure that the connection is kept open for new changes
and updates.

The continuous feed's response is a little different than the other feed types
to simplify the job of the client - each line of the response is either empty
or a JSON object representing a single change, as found in the normal feed's
results.

.. code-block:: http

    GET /somedatabase/_changes?feed=continuous HTTP/1.1

.. code-block:: javascript

    {"seq":"1-g1AAAAF9eJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MSGXAqSVIAkkn2IFUZzIkMuUAee5pRqnGiuXkKA2dpXkpqWmZeagpu_Q4g_fGEbEkAqaqH2sIItsXAyMjM2NgUUwdOU_JYgCRDA5ACGjQfn30QlQsgKvcTVnkAovI-YZUPICpBvs0CAN1eY_c","id":"fresh","changes":[{"rev":"5-g1AAAAHxeJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBOZcoEC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HkV_kkGyZWqSEXH6E0D666H6GcH6DYyMzIyNTUnwRR4LkGRoAFJAg-YjwiMtOdXCwJyU8ICYtABi0n6EnwzSzIxS00yI8hPEjAMQM-5nJTIQUPkAovI_UGUWAA0SgOI","id":"updated","changes":[{"rev":"2-7051cbe5c8faecd085a3fa619e6e6337"}]}
    {"seq":"3-g1AAAAHReJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBOZcoEC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HkV_kkGyZWqSEXH6E0D660H6ExlwqspjAZIMDUAKqHA-yCZGiEuTUy0MzEnxL8SkBRCT9iPcbJBmZpSaZkKUmyFmHICYcZ-wux9AVIJ8mAUABgp6XQ","id":"deleted","changes":[{"rev":"2-eec205a9d413992850a6e32678485900"}],"deleted":true}
    ... tum tee tum ...
    {"seq":"6-g1AAAAIreJyVkEsKwjAURWMrqCOXoCuQ9MU0OrI70XyppcaRY92J7kR3ojupaVNopRQsgRd4yTlwb44QmqahQnN7VjpKImAr7E6Uu4eAI7EoiiJLQx6c3GIiuVJcx93vvQqxdFPsaguqLAY04YwpNLtYpc3RatXPJyW__-EFllst4D_-UPLXmh9VPAaICaEDUtixm-jmLie6N30YqTeYDenDmx7e9GwyYRODNuu_MnnHyzverV6AMkPkAMfHO1rdUAKUkqhLZV-_0o5j","id":"updated","changes":[{"rev":"3-825cb35de44c433bfb2df415563a19de"}]}

Obviously, `... tum tee tum ...` does not appear in the actual response, but
represents a long pause before the change with seq 6 occurred.

.. _Change Notifications in the book CouchDB The Definitive Guide: http://guide.couchdb.org/draft/notifications.html

.. _changes/eventsource:

Event Source
------------

The `eventsource` feed provides push notifications that can be consumed in
the form of DOM events in the browser. Refer to the `W3C eventsource
specification`_ for further details. CouchDB also honours the ``Last-Event-ID``
parameter.

.. code-block:: http

    GET /somedatabase/_changes?feed=eventsource HTTP/1.1

.. code-block:: javascript

    // define the event handling function
    if (window.EventSource) {

        var source = new EventSource("/somedatabase/_changes?feed=eventsource");
        source.onerror = function(e) {
            alert('EventSource failed.');
        };

        var results = [];
        var sourceListener = function(e) {
            var data = JSON.parse(e.data);
            results.push(data);
        };

        // start listening for events
        source.addEventListener('message', sourceListener, false);

        // stop listening for events
        source.removeEventListener('message', sourceListener, false);

    }

If you set a heartbeat interval (using the ``heartbeat`` query argument),
CouchDB will send a ``hearbeat`` event that you can subscribe to with:

.. code-block:: javascript

    source.addEventListener('heartbeat', function () {}, false);

This can be monitored by the client application to restart the EventSource
connection if needed (i.e. if the TCP connection gets stuck in a half-open
state).

.. note::
    EventSource connections are subject to cross-origin resource sharing
    restrictions. You might need to configure :ref:`CORS support
    <cors>` to get the EventSource to work in your application.

.. _W3C eventsource specification: http://www.w3.org/TR/eventsource/

.. _changes/filter:

Filtering
=========

You can filter the contents of the changes feed in a number of ways. The
most basic way is to specify one or more document IDs to the query. This
causes the returned structure value to only contain changes for the
specified IDs. Note that the value of this query argument should be a
JSON formatted array.

You can also filter the ``_changes`` feed by defining a filter function
within a design document. The specification for the filter is the same
as for replication filters. You specify the name of the filter function
to the ``filter`` parameter, specifying the design document name and
:ref:`filter name <filterfun>`. For example:

.. code-block:: http

    GET /db/_changes?filter=design_doc/filtername HTTP/1.1

Additionally, a couple of built-in filters are available and described
below.

.. _changes/filter/doc_ids:

_doc_ids
--------

This filter accepts only changes for documents which ID in specified in
``doc_ids`` query parameter or payload's object array. See
:post:`/{db}/_changes` for an example.

.. _changes/filter/selector:

_selector
---------

.. versionadded:: 2.0

This filter accepts only changes for documents which match a specified
selector, defined using the same :ref:`selector
syntax <find/selectors>` used for :ref:`_find <api/db/_find>`.

This is significantly more efficient than using a JavaScript filter
function and is the recommended option if filtering on document attributes only.

Note that, unlike JavaScript filters, selectors do not have access to the
request object.

**Request**:

.. code-block:: http

    POST /recipes/_changes?filter=_selector HTTP/1.1
    Content-Type: application/json
    Host: localhost:5984

    {
        "selector": { "_id": { "$regex": "^_design/" } }
    }

**Response**:

.. code-block:: http

    HTTP/1.1 200 OK
    Cache-Control: must-revalidate
    Content-Type: application/json
    Date: Tue, 06 Sep 2016 20:03:23 GMT
    Etag: "1H8RGBCK3ABY6ACDM7ZSC30QK"
    Server: CouchDB (Erlang OTP/18)
    Transfer-Encoding: chunked

    {
        "last_seq": "11-g1AAAAIreJyVkEEKwjAQRUOrqCuPoCeQZGIaXdmbaNIk1FLjyrXeRG-iN9Gb1LQRaimFlsAEJnkP_s8RQtM0VGhuz0qTmABfYXdI7h4CgeSiKIosDUVwcotJIpQSOmp_71TIpZty97OgymJAU8G5QrOLVdocrVbdfFzy-wYvcbLVEvrxh5K_NlJggIhSNiCFHbmJbu5yonttMoneYD6kD296eNOzzoRNBNqse2Xyjpd3vP96AcYNTQY4Pt5RdTOuHIwCY5S0qewLwY6OaA",
        "pending": 0,
        "results": [
            {
                "changes": [
                    {
                        "rev": "10-304cae84fd862832ea9814f02920d4b2"
                    }
                ],
                "id": "_design/ingredients",
                "seq": "8-g1AAAAHxeJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBOZcoEC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HkV_kkGyZWqSEXH6E0D666H6GcH6DYyMzIyNTUnwRR4LkGRoAFJAg-ZnJTIQULkAonI_ws0GaWZGqWkmRLkZYsYBiBn3Cdv2AKIS7ENWsG2mxkampsaGmLqyAOYpgEo"
            },
            {
                "changes": [
                    {
                        "rev": "123-6f7c1b7c97a9e4f0d22bdf130e8fd817"
                    }
                ],
                "deleted": true,
                "id": "_design/cookbook",
                "seq": "9-g1AAAAHxeJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBOZcoEC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HkV_kkGyZWqSEXH6E0D661F8YWBkZGZsbEqCL_JYgCRDA5ACGjQ_K5GBgMoFEJX7EW42SDMzSk0zIcrNEDMOQMy4T9i2BxCVYB-ygm0zNTYyNTU2xNSVBQDnK4BL"
            },
            {
                "changes": [
                    {
                        "rev": "6-5b8a52c22580e922e792047cff3618f3"
                    }
                ],
                "deleted": true,
                "id": "_design/meta",
                "seq": "11-g1AAAAIReJyVkE0OgjAQRiegUVceQU9g-mOpruQm2tI2SLCuXOtN9CZ6E70JFmpCCCFCmkyTdt6bfJMDwDQNFcztWWkcY8JXyB2cu49AgFwURZGloQhO7mGSCKWEjtrtnQq5dFXufhaoLIZoKjhXMLtYpc3RatXNxyW_b_ASJVstST_-UPLXRgpESEQpG5DCjlyFm7uc6F6bTKI3iA_Zhzc9vOlZZ0ImItqse2Xyjpd3vDMBfzo_vrPawLiaxihhjOI2lX0BirqHbg"
            }
        ]
    }

.. _changes/filter/selector/missing:

Missing selector
################

If the selector object is missing from the request body,
the error message is similar to the following example:

.. code-block:: json

   {
      "error": "bad request",
      "reason": "Selector must be specified in POST payload"
   }

.. _changes/filter/selector/invalidjson:

Not a valid JSON object
#######################

If the selector object is not a well-formed JSON object,
the error message is similar to the following example:

.. code-block:: json

   {
      "error": "bad request",
      "reason": "Selector error: expected a JSON object"
   }

.. _changes/filter/selector/invalidselector:

Not a valid selector
####################

If the selector object does not contain a valid selection expression,
the error message is similar to the following example:

.. code-block:: json

   {
      "error": "bad request",
      "reason": "Selector error: expected a JSON object"
   }

.. _changes/filter/design:

_design
-------

The ``_design`` filter accepts only changes for any design document within the
requested database.

**Request**:

.. code-block:: http

    GET /recipes/_changes?filter=_design HTTP/1.1
    Accept: application/json
    Host: localhost:5984

**Response**:

.. code-block:: http

    HTTP/1.1 200 OK
    Cache-Control: must-revalidate
    Content-Type: application/json
    Date: Tue, 06 Sep 2016 12:55:12 GMT
    ETag: "ARIHFWL3I7PIS0SPVTFU6TLR2"
    Server: CouchDB (Erlang OTP)
    Transfer-Encoding: chunked

    {
        "last_seq": "11-g1AAAAIreJyVkEEKwjAQRUOrqCuPoCeQZGIaXdmbaNIk1FLjyrXeRG-iN9Gb1LQRaimFlsAEJnkP_s8RQtM0VGhuz0qTmABfYXdI7h4CgeSiKIosDUVwcotJIpQSOmp_71TIpZty97OgymJAU8G5QrOLVdocrVbdfFzy-wYvcbLVEvrxh5K_NlJggIhSNiCFHbmJbu5yonttMoneYD6kD296eNOzzoRNBNqse2Xyjpd3vP96AcYNTQY4Pt5RdTOuHIwCY5S0qewLwY6OaA",
        "pending": 0,
        "results": [
            {
                "changes": [
                    {
                        "rev": "10-304cae84fd862832ea9814f02920d4b2"
                    }
                ],
                "id": "_design/ingredients",
                "seq": "8-g1AAAAHxeJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBOZcoEC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HkV_kkGyZWqSEXH6E0D666H6GcH6DYyMzIyNTUnwRR4LkGRoAFJAg-ZnJTIQULkAonI_ws0GaWZGqWkmRLkZYsYBiBn3Cdv2AKIS7ENWsG2mxkampsaGmLqyAOYpgEo"
            },
            {
                "changes": [
                    {
                        "rev": "123-6f7c1b7c97a9e4f0d22bdf130e8fd817"
                    }
                ],
                "deleted": true,
                "id": "_design/cookbook",
                "seq": "9-g1AAAAHxeJzLYWBg4MhgTmHgz8tPSTV0MDQy1zMAQsMcoARTIkOS_P___7MymBOZcoEC7MmJKSmJqWaYynEakaQAJJPsoaYwgE1JM0o1TjQ3T2HgLM1LSU3LzEtNwa3fAaQ_HkV_kkGyZWqSEXH6E0D661F8YWBkZGZsbEqCL_JYgCRDA5ACGjQ_K5GBgMoFEJX7EW42SDMzSk0zIcrNEDMOQMy4T9i2BxCVYB-ygm0zNTYyNTU2xNSVBQDnK4BL"
            },
            {
                "changes": [
                    {
                        "rev": "6-5b8a52c22580e922e792047cff3618f3"
                    }
                ],
                "deleted": true,
                "id": "_design/meta",
                "seq": "11-g1AAAAIReJyVkE0OgjAQRiegUVceQU9g-mOpruQm2tI2SLCuXOtN9CZ6E70JFmpCCCFCmkyTdt6bfJMDwDQNFcztWWkcY8JXyB2cu49AgFwURZGloQhO7mGSCKWEjtrtnQq5dFXufhaoLIZoKjhXMLtYpc3RatXNxyW_b_ASJVstST_-UPLXRgpESEQpG5DCjlyFm7uc6F6bTKI3iA_Zhzc9vOlZZ0ImItqse2Xyjpd3vDMBfzo_vrPawLiaxihhjOI2lX0BirqHbg"
            }
        ]
    }

.. _changes/filter/view:

_view
-----

.. versionadded:: 1.2

The special filter ``_view`` allows to use existing
:ref:`map function <mapfun>` as the :ref:`filter <filterfun>`. If the map
function emits anything for the processed document it counts as accepted and
the changes event emits to the feed. For most use-practice cases `filter`
functions are very similar to `map` ones, so this feature helps to reduce
amount of duplicated code.

.. warning::
    While :ref:`map functions <mapfun>` doesn't process the design documents,
    using ``_view`` filter forces them to do this. You need to be sure, that
    they are ready to handle documents with *alien* structure without panic.

.. note::
    Using ``_view`` filter doesn't queries the view index files, so you cannot
    use common :ref:`view query parameters <api/ddoc/view>` to additionally
    filter the changes feed by index key. Also, CouchDB doesn't returns
    the result instantly as it does for views - it really uses the specified
    map function as filter.

    Moreover, you cannot make such filters dynamic e.g. process the request
    query parameters or handle the :ref:`userctx_object` - the map function is
    only operates with the document.

**Request**:

.. code-block:: http

    GET /recipes/_changes?filter=_view&view=ingredients/by_recipe HTTP/1.1
    Accept: application/json
    Host: localhost:5984

**Response**:

.. code-block:: http

    HTTP/1.1 200 OK
    Cache-Control: must-revalidate
    Content-Type: application/json
    Date: Tue, 06 Sep 2016 12:57:56 GMT
    ETag: "ARIHFWL3I7PIS0SPVTFU6TLR2"
    Server: CouchDB (Erlang OTP)
    Transfer-Encoding: chunked

    {
        "last_seq": "11-g1AAAAIreJyVkEEKwjAQRUOrqCuPoCeQZGIaXdmbaNIk1FLjyrXeRG-iN9Gb1LQRaimFlsAEJnkP_s8RQtM0VGhuz0qTmABfYXdI7h4CgeSiKIosDUVwcotJIpQSOmp_71TIpZty97OgymJAU8G5QrOLVdocrVbdfFzy-wYvcbLVEvrxh5K_NlJggIhSNiCFHbmJbu5yonttMoneYD6kD296eNOzzoRNBNqse2Xyjpd3vP96AcYNTQY4Pt5RdTOuHIwCY5S0qewLwY6OaA",
        "results": [
            {
                "changes": [
                    {
                        "rev": "13-bcb9d6388b60fd1e960d9ec4e8e3f29e"
                    }
                ],
                "id": "SpaghettiWithMeatballs",
                "seq": "11-g1AAAAIReJyVkE0OgjAQRiegUVceQU9g-mOpruQm2tI2SLCuXOtN9CZ6E70JFmpCCCFCmkyTdt6bfJMDwDQNFcztWWkcY8JXyB2cu49AgFwURZGloQhO7mGSCKWEjtrtnQq5dFXufhaoLIZoKjhXMLtYpc3RatXNxyW_b_ASJVstST_-UPLXRgpESEQpG5DCjlyFm7uc6F6bTKI3iA_Zhzc9vOlZZ0ImItqse2Xyjpd3vDMBfzo_vrPawLiaxihhjOI2lX0BirqHbg"
            }
        ]
    }
