En esta guía, puede aprender sobre las diferencias entre PyMongoArrow y el driver de PyMongo. Esta guía asume familiaridad con lo básico PyMongo and MongoDB concepts.
Lectura de datos
La manera más básica de leer datos usando PyMongo es:
coll = db.benchmark f = list(coll.find({}, projection={"_id": 0})) table = pyarrow.Table.from_pylist(f)
Esto funciona, pero hay que excluir el _id campo, de lo contrario obtendrá el siguiente error:
pyarrow.lib.ArrowInvalid: Could not convert ObjectId('642f2f4720d92a85355671b3') with type ObjectId: did not recognize Python value type when inferring an Arrow data type
El siguiente ejemplo de código muestra una solución alternativa para el error anterior al usar PyMongo:
f = list(coll.find({})) for doc in f: doc["_id"] = str(doc["_id"]) ... table = pyarrow.Table.from_pylist(f) print(table) pyarrow.Table _id: string x: int64 y: double
Aunque esto evita el error, una desventaja es que Arrow no puede identificar que _id es un ObjectId, como se indica en el esquema que muestra _id como un string.
PyMongoArrow admite BSON types a través de Arrow o Tipos de Extensión de Pandas. Esto te permite evitar la solución alternativa anterior.
from pymongoarrow.types import ObjectIdType schema = Schema({"_id": ObjectIdType(), "x": pyarrow.int64(), "y": pyarrow.float64()}) table = find_arrow_all(coll, {}, schema=schema) print(table) pyarrow.Table _id: extension<arrow.py_extension_type<ObjectIdType>> x: int64 y: double
Con este método, Arrow identifica correctamente el tipo. Su uso es limitado para tipos de extensión no numéricos, pero evita conversiones innecesarias para ciertas operaciones, como la ordenación de fechas y horas.
f = list(coll.find({}, projection={"_id": 0, "x": 0})) naive_table = pyarrow.Table.from_pylist(f) schema = Schema({"time": pyarrow.timestamp("ms")}) table = find_arrow_all(coll, {}, schema=schema) assert ( table.sort_by([("time", "ascending")])["time"] == naive_table["time"].cast(pyarrow.timestamp("ms")).sort() )
Además, PyMongoArrow es compatible con los tipos de extensión de Pandas. Con PyMongo, un valor Decimal128 se comporta de la siguiente manera:
coll = client.test.test coll.insert_many([{"value": Decimal128(str(i))} for i in range(200)]) cursor = coll.find({}) df = pd.DataFrame(list(cursor)) print(df.dtypes) # _id object # value object
El equivalente en PyMongoArrow es:
from pymongoarrow.api import find_pandas_all coll = client.test.test coll.insert_many([{"value": Decimal128(str(i))} for i in range(200)]) df = find_pandas_all(coll, {}) print(df.dtypes) # _id bson_PandasObjectId # value bson_PandasDecimal128
En ambos casos, los valores subyacentes son del tipo de la clase BSON:
print(df["value"][0]) Decimal128("0")
Escribir datos
Escribir datos desde una tabla Arrow usando PyMongo se ve así:
data = arrow_table.to_pylist() db.collname.insert_many(data)
El equivalente en PyMongoArrow es:
from pymongoarrow.api import write write(db.collname, arrow_table)
A partir de PyMongoArrow 1.0, la principal ventaja de utilizar la función write es que itera sobre la arrow table, dataframe o arreglo numpy, y no convierte todo el objeto a una lista.
Puntos de referencia
Las siguientes mediciones se realizaron con PyMongoArrow versión 1.0 y PyMongo versión 4.4. En cuanto a las inserciones, la biblioteca funciona prácticamente igual que con PyMongo convencional y utiliza la misma cantidad de memoria.
ProfileInsertSmall.peakmem_insert_conventional 107M ProfileInsertSmall.peakmem_insert_arrow 108M ProfileInsertSmall.time_insert_conventional 202±0.8ms ProfileInsertSmall.time_insert_arrow 181±0.4ms ProfileInsertLarge.peakmem_insert_arrow 127M ProfileInsertLarge.peakmem_insert_conventional 125M ProfileInsertLarge.time_insert_arrow 425±1ms ProfileInsertLarge.time_insert_conventional 440±1ms
Para lecturas, la librería es más lenta para documentos pequeños y documentos anidados, pero más rápida para documentos grandes. Utiliza menos memoria en todos los casos.
ProfileReadSmall.peakmem_conventional_arrow 85.8M ProfileReadSmall.peakmem_to_arrow 83.1M ProfileReadSmall.time_conventional_arrow 38.1±0.3ms ProfileReadSmall.time_to_arrow 60.8±0.3ms ProfileReadLarge.peakmem_conventional_arrow 138M ProfileReadLarge.peakmem_to_arrow 106M ProfileReadLarge.time_conventional_ndarray 243±20ms ProfileReadLarge.time_to_arrow 186±0.8ms ProfileReadDocument.peakmem_conventional_arrow 209M ProfileReadDocument.peakmem_to_arrow 152M ProfileReadDocument.time_conventional_arrow 865±7ms ProfileReadDocument.time_to_arrow 937±1ms