|
30 | 30 | helpers,
|
31 | 31 | message)
|
32 | 32 | from pymongo.bulk import BulkOperationBuilder, _Bulk
|
33 |
| -from pymongo.command_cursor import CommandCursor |
| 33 | +from pymongo.command_cursor import CommandCursor, RawBatchCommandCursor |
34 | 34 | from pymongo.collation import validate_collation_or_none
|
35 |
| -from pymongo.cursor import Cursor, RawBSONCursor |
| 35 | +from pymongo.cursor import Cursor, RawBatchCursor |
36 | 36 | from pymongo.errors import ConfigurationError, InvalidName, OperationFailure
|
37 | 37 | from pymongo.helpers import _check_write_command_response
|
38 | 38 | from pymongo.helpers import _UNICODE_REPLACE_CODEC_OPTIONS
|
@@ -1278,25 +1278,25 @@ def find(self, *args, **kwargs):
|
1278 | 1278 | """
|
1279 | 1279 | return Cursor(self, *args, **kwargs)
|
1280 | 1280 |
|
1281 |
| - def find_raw(self, *args, **kwargs): |
| 1281 | + def find_raw_batches(self, *args, **kwargs): |
1282 | 1282 | """Query the database and retrieve batches of raw BSON.
|
1283 | 1283 |
|
1284 | 1284 | Takes the same parameters as :meth:`find` but returns a
|
1285 |
| - :class:`~pymongo.cursor.RawBSONCursor`. |
| 1285 | + :class:`~pymongo.cursor.RawBatchCursor`. |
1286 | 1286 |
|
1287 | 1287 | This example demonstrates how to work with raw batches, but in practice
|
1288 | 1288 | raw batches should be passed to an external library that can decode
|
1289 | 1289 | BSON into another data type, rather than used with PyMongo's
|
1290 | 1290 | :mod:`bson` module.
|
1291 | 1291 |
|
1292 | 1292 | >>> import bson
|
1293 |
| - >>> cursor = db.test.find_raw() |
| 1293 | + >>> cursor = db.test.find_raw_batches() |
1294 | 1294 | >>> for batch in cursor:
|
1295 | 1295 | ... print(bson.decode_all(batch))
|
1296 | 1296 |
|
1297 | 1297 | .. versionadded:: 3.6
|
1298 | 1298 | """
|
1299 |
| - return RawBSONCursor(self, *args, **kwargs) |
| 1299 | + return RawBatchCursor(self, *args, **kwargs) |
1300 | 1300 |
|
1301 | 1301 | def parallel_scan(self, num_cursors, **kwargs):
|
1302 | 1302 | """Scan this entire collection in parallel.
|
@@ -1821,6 +1821,69 @@ def options(self):
|
1821 | 1821 |
|
1822 | 1822 | return options
|
1823 | 1823 |
|
| 1824 | + def _aggregate(self, pipeline, cursor_class, first_batch_size, **kwargs): |
| 1825 | + if not isinstance(pipeline, list): |
| 1826 | + raise TypeError("pipeline must be a list") |
| 1827 | + |
| 1828 | + if "explain" in kwargs: |
| 1829 | + raise ConfigurationError("The explain option is not supported. " |
| 1830 | + "Use Database.command instead.") |
| 1831 | + collation = validate_collation_or_none(kwargs.pop('collation', None)) |
| 1832 | + |
| 1833 | + cmd = SON([("aggregate", self.__name), |
| 1834 | + ("pipeline", pipeline)]) |
| 1835 | + |
| 1836 | + # Remove things that are not command options. |
| 1837 | + batch_size = common.validate_non_negative_integer_or_none( |
| 1838 | + "batchSize", kwargs.pop("batchSize", None)) |
| 1839 | + use_cursor = common.validate_boolean( |
| 1840 | + "useCursor", kwargs.pop("useCursor", True)) |
| 1841 | + # If the server does not support the "cursor" option we |
| 1842 | + # ignore useCursor and batchSize. |
| 1843 | + with self._socket_for_reads() as (sock_info, slave_ok): |
| 1844 | + if sock_info.max_wire_version > 0: |
| 1845 | + if use_cursor: |
| 1846 | + if "cursor" not in kwargs: |
| 1847 | + kwargs["cursor"] = {} |
| 1848 | + if first_batch_size is not None: |
| 1849 | + kwargs["cursor"]["batchSize"] = first_batch_size |
| 1850 | + |
| 1851 | + dollar_out = pipeline and '$out' in pipeline[-1] |
| 1852 | + if (sock_info.max_wire_version >= 5 and dollar_out and |
| 1853 | + self.write_concern): |
| 1854 | + cmd['writeConcern'] = self.write_concern.document |
| 1855 | + |
| 1856 | + cmd.update(kwargs) |
| 1857 | + |
| 1858 | + # Apply this Collection's read concern if $out is not in the |
| 1859 | + # pipeline. |
| 1860 | + if sock_info.max_wire_version >= 4 and 'readConcern' not in cmd: |
| 1861 | + if dollar_out: |
| 1862 | + result = self._command(sock_info, cmd, slave_ok, |
| 1863 | + parse_write_concern_error=True, |
| 1864 | + collation=collation) |
| 1865 | + else: |
| 1866 | + result = self._command(sock_info, cmd, slave_ok, |
| 1867 | + read_concern=self.read_concern, |
| 1868 | + collation=collation) |
| 1869 | + else: |
| 1870 | + result = self._command(sock_info, cmd, slave_ok, |
| 1871 | + parse_write_concern_error=dollar_out, |
| 1872 | + collation=collation) |
| 1873 | + |
| 1874 | + if "cursor" in result: |
| 1875 | + cursor = result["cursor"] |
| 1876 | + else: |
| 1877 | + # Pre-MongoDB 2.6. Fake a cursor. |
| 1878 | + cursor = { |
| 1879 | + "id": 0, |
| 1880 | + "firstBatch": result["result"], |
| 1881 | + "ns": self.full_name, |
| 1882 | + } |
| 1883 | + |
| 1884 | + return cursor_class( |
| 1885 | + self, cursor, sock_info.address).batch_size(batch_size or 0) |
| 1886 | + |
1824 | 1887 | def aggregate(self, pipeline, **kwargs):
|
1825 | 1888 | """Perform an aggregation using the aggregation framework on this
|
1826 | 1889 | collection.
|
@@ -1892,66 +1955,34 @@ def aggregate(self, pipeline, **kwargs):
|
1892 | 1955 | .. _aggregate command:
|
1893 | 1956 | http://docs.mongodb.org/manual/applications/aggregation
|
1894 | 1957 | """
|
1895 |
| - if not isinstance(pipeline, list): |
1896 |
| - raise TypeError("pipeline must be a list") |
1897 |
| - |
1898 |
| - if "explain" in kwargs: |
1899 |
| - raise ConfigurationError("The explain option is not supported. " |
1900 |
| - "Use Database.command instead.") |
1901 |
| - collation = validate_collation_or_none(kwargs.pop('collation', None)) |
| 1958 | + return self._aggregate(pipeline, |
| 1959 | + CommandCursor, |
| 1960 | + kwargs.get('batchSize'), |
| 1961 | + **kwargs) |
1902 | 1962 |
|
1903 |
| - cmd = SON([("aggregate", self.__name), |
1904 |
| - ("pipeline", pipeline)]) |
1905 |
| - |
1906 |
| - # Remove things that are not command options. |
1907 |
| - batch_size = common.validate_positive_integer_or_none( |
1908 |
| - "batchSize", kwargs.pop("batchSize", None)) |
1909 |
| - use_cursor = common.validate_boolean( |
1910 |
| - "useCursor", kwargs.pop("useCursor", True)) |
1911 |
| - # If the server does not support the "cursor" option we |
1912 |
| - # ignore useCursor and batchSize. |
1913 |
| - with self._socket_for_reads() as (sock_info, slave_ok): |
1914 |
| - if sock_info.max_wire_version > 0: |
1915 |
| - if use_cursor: |
1916 |
| - if "cursor" not in kwargs: |
1917 |
| - kwargs["cursor"] = {} |
1918 |
| - if batch_size is not None: |
1919 |
| - kwargs["cursor"]["batchSize"] = batch_size |
| 1963 | + def aggregate_raw_batches(self, pipeline, **kwargs): |
| 1964 | + """Perform an aggregation and retrieve batches of raw BSON. |
1920 | 1965 |
|
1921 |
| - dollar_out = pipeline and '$out' in pipeline[-1] |
1922 |
| - if (sock_info.max_wire_version >= 5 and dollar_out and |
1923 |
| - self.write_concern): |
1924 |
| - cmd['writeConcern'] = self.write_concern.document |
| 1966 | + Takes the same parameters as :meth:`aggregate` but returns a |
| 1967 | + :class:`~pymongo.cursor.RawBatchCursor`. |
1925 | 1968 |
|
1926 |
| - cmd.update(kwargs) |
| 1969 | + This example demonstrates how to work with raw batches, but in practice |
| 1970 | + raw batches should be passed to an external library that can decode |
| 1971 | + BSON into another data type, rather than used with PyMongo's |
| 1972 | + :mod:`bson` module. |
1927 | 1973 |
|
1928 |
| - # Apply this Collection's read concern if $out is not in the |
1929 |
| - # pipeline. |
1930 |
| - if sock_info.max_wire_version >= 4 and 'readConcern' not in cmd: |
1931 |
| - if dollar_out: |
1932 |
| - result = self._command(sock_info, cmd, slave_ok, |
1933 |
| - parse_write_concern_error=True, |
1934 |
| - collation=collation) |
1935 |
| - else: |
1936 |
| - result = self._command(sock_info, cmd, slave_ok, |
1937 |
| - read_concern=self.read_concern, |
1938 |
| - collation=collation) |
1939 |
| - else: |
1940 |
| - result = self._command(sock_info, cmd, slave_ok, |
1941 |
| - parse_write_concern_error=dollar_out, |
1942 |
| - collation=collation) |
| 1974 | + >>> import bson |
| 1975 | + >>> cursor = db.test.aggregate_raw_batches([ |
| 1976 | + ... {'$project': {'x': {'$multiply': [2, '$x']}}}]) |
| 1977 | + >>> for batch in cursor: |
| 1978 | + ... print(bson.decode_all(batch)) |
1943 | 1979 |
|
1944 |
| - if "cursor" in result: |
1945 |
| - cursor = result["cursor"] |
1946 |
| - else: |
1947 |
| - # Pre-MongoDB 2.6. Fake a cursor. |
1948 |
| - cursor = { |
1949 |
| - "id": 0, |
1950 |
| - "firstBatch": result["result"], |
1951 |
| - "ns": self.full_name, |
1952 |
| - } |
1953 |
| - return CommandCursor( |
1954 |
| - self, cursor, sock_info.address).batch_size(batch_size or 0) |
| 1980 | + .. versionadded:: 3.6 |
| 1981 | + """ |
| 1982 | + return self._aggregate(pipeline, |
| 1983 | + RawBatchCommandCursor, |
| 1984 | + 0, |
| 1985 | + **kwargs) |
1955 | 1986 |
|
1956 | 1987 | def group(self, key, condition, initial, reduce, finalize=None, **kwargs):
|
1957 | 1988 | """Perform a query similar to an SQL *group by* operation.
|
|
0 commit comments