es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Obteniendo un error de tamaño de BSONObj incluso con la opción allowDiskUse true.

Tengo una colección con 300 millones de documentos, cada uno de los cuales tiene un campo user_id de la siguiente manera:

{
"user_id": "1234567",
// y otros campos
}

Quiero obtener una lista de user_ids únicos en la colección, pero el siguiente comando de mongo shell resulta en un error.


db.collection.aggregate([
{ $group: { _id: null, user_ids: { $addToSet: "$user_id" } } }
], { allowDiskUse: true });


2021-11-23T14:50:28.163+0900 E QUERY [js] uncaught exception: Error: command failed: {
"ok" : 0,
"errmsg" : "Error on remote shard <host>:<port> :: caused by :: BSONObj size: 46032166 (0x2BE6526) is invalid. Size must be between 0 and 16793600(16MB) First element: _id: null",
"code" : 10334,
"codeName" : "BSONObjectTooLarge",
"operationTime" : Timestamp(1637646628, 64),
...
} : aggregate failed :

¿Por qué ocurre el error incluso con la opción allowDiskUse: true?
La versión de la base de datos es 4.2.16.

Tags:  ,

Answer

  1. Avatar for davy.ai

    El error está ocurriendo porque el conjunto de resultados del pipeline de agregación supera el tamaño máximo de objeto BSON de 16MB que admite MongoDB. Como el número de user_ids únicos en la colección es muy grande (hasta 300 millones), el conjunto resultante de user_ids supera el tamaño máximo de objeto BSON, lo que provoca el mensaje de error.

    La opción allowDiskUse: true no ayuda en este caso ya que permite que el pipeline de agregación escriba datos temporales en disco, pero no aumenta el tamaño máximo de objeto BSON.

    Para resolver este problema, un enfoque posible sería dividir el pipeline de agregación en fragmentos más pequeños, de manera que cada fragmento devuelva un subconjunto de los user_ids únicos en la colección. Por ejemplo, podríamos dividir la colección en lotes de 10 millones de documentos y ejecutar el siguiente pipeline de agregación para cada lote:

    db.collection.find().limit(10000000).aggregate([
      { $group: { _id: null, user_ids: { $addToSet: "$user_id" } } }
    ], { allowDiskUse: true });
    

    Luego, podríamos combinar los resultados de cada lote en una lista única de user_ids únicos utilizando un script del lado del cliente.

    Otro enfoque sería utilizar un trabajo Map-Reduce para obtener la lista única de user_ids en la colección. Sin embargo, este enfoque puede no ser el más eficiente ya que Map-Reduce puede ser más lento que el framework de agregación.

Comments are closed.