sql >> Base de Datos >  >> NoSQL >> MongoDB

Población de mangosta frente a anidación de objetos

Lo primero que debe entender sobre la población de mangostas es que no es magia, sino solo un método conveniente que le permite recuperar información relacionada sin tener que hacerlo todo usted mismo.

El concepto es esencialmente para usar cuando decida que necesitará colocar los datos en una colección separada en lugar de incrustarlos, y sus consideraciones principales deben ser típicamente el tamaño del documento o cuando esa información relacionada esté sujeta a actualizaciones frecuentes que harían mantener los datos incrustados difíciles de manejar.

La parte "no mágica" es que, esencialmente, lo que sucede debajo de las sábanas es que cuando "hace referencia" a otra fuente, la función de llenado realiza una consulta/consultas adicionales a esa colección "relacionada" para "fusionar" esos resultados del padre objeto que ha recuperado. Puede hacerlo usted mismo, pero el método está ahí para simplificar la tarea. La consideración obvia de "rendimiento" es que no hay un solo viaje de ida y vuelta a la base de datos (instancia de MongoDB) para recuperar toda la información. Siempre hay más de uno.

Como muestra, tome dos colecciones:

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        ObjectId("5392fee10ff066b7d533a766"),
        ObjectId("5392fefe0ff066b7d533a767")
    ]
}

Y los artículos:

{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 }
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }

Lo "mejor" que se puede hacer con un modelo "referenciado" o el uso de poblar (debajo del capó) es esto:

var order = db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
order.items = db.items.find({ "_id": { "$in": order.items } ).toArray();

Entonces, claramente hay "al menos" dos consultas y operaciones para "unir" esos datos.

El concepto de incrustación es esencialmente la respuesta de MongoDB a cómo lidiar con la no compatibilidad con "uniones". Entonces, en lugar de dividir los datos en colecciones normalizadas, intente incrustar los datos "relacionados" directamente dentro del documento que los usa. Las ventajas aquí son que hay una única operación de "lectura" para recuperar la información "relacionada", y también un único punto de operaciones de "escritura" para actualizar las entradas "principal" y "secundaria", aunque a menudo no es posible escribir en ellas. "muchos" hijos a la vez sin procesar "listas" en el cliente o aceptar "múltiples" operaciones de escritura, y preferiblemente en procesamiento "por lotes".

Entonces, los datos se ven así (en comparación con el ejemplo anterior):

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        { "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 },
        { "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
    ]
}

Por lo tanto, obtener los datos es solo una cuestión de:

db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });

Los pros y los contras de cualquiera siempre dependerán en gran medida del patrón de uso de su aplicación. Pero de un vistazo:

Incrustación

  • El tamaño total del documento con datos incrustados normalmente no excederá los 16 MB de almacenamiento (el límite de BSON) o, de lo contrario, (como guía) tendrá arreglos que contengan 500 o más entradas.

  • Los datos incrustados generalmente no requieren cambios frecuentes. Por lo tanto, podría vivir con la "duplicación" que proviene de la desnormalización que no resulta en la necesidad de actualizar esos "duplicados" con la misma información en muchos documentos principales solo para invocar un cambio.

  • Los datos relacionados se utilizan con frecuencia en asociación con el padre. Lo que significa que si sus casos de "lectura/escritura" casi siempre necesitan "leer/escribir" tanto para el padre como para el hijo, entonces tiene sentido incrustar los datos para las operaciones atómicas.

Referencia

  • Los datos relacionados siempre superarán el límite de BSON de 16 MB. Siempre puede considerar un enfoque híbrido de "bucketing", pero no se puede infringir el límite rígido general del documento principal. Los casos comunes son "publicación" y "comentarios" donde se espera que la actividad de "comentario" sea muy grande.

  • Los datos relacionados necesitan una actualización periódica. O esencialmente el caso en el que "normaliza" porque esos datos se "comparten" entre muchos padres y los datos "relacionados" se cambian con la frecuencia suficiente para que no sea práctico actualizar los elementos incrustados en cada "principal" donde aparece ese elemento "secundario". . El caso más fácil es simplemente hacer referencia al "hijo" y hacer el cambio una vez.

  • Hay una clara separación de lecturas y escrituras. En el caso de que tal vez no requiera siempre esa información "relacionada" cuando lea el "padre" o no necesite modificar siempre el "padre" cuando escriba al niño, podría haber una buena razón para separar el modelo. como se hace referencia. Además, si hay un deseo general de actualizar muchos "subdocumentos" a la vez en los que esos "subdocumentos" son en realidad referencias a otra colección, entonces, con bastante frecuencia, la implementación es más eficiente cuando los datos están en un archivo separado. colección.

Por lo tanto, en realidad hay una discusión mucho más amplia sobre los "pros/contras" para cada posición en la documentación de MongoDB sobre el modelado de datos, que cubre varios casos de uso y formas de abordar el uso del modelo incrustado o referenciado como lo admite el método de población.

Con suerte, los "puntos" son útiles, pero la recomendación general es considerar los patrones de uso de datos de su aplicación y elegir lo que sea mejor. Tener la "opción" de incrustar "debería" ser la razón por la que eligió MongoDB, pero en realidad será la forma en que su aplicación "utilice los datos" lo que tome la decisión de qué método se adapta a qué parte de su modelado de datos (ya que no lo es). "todo o nada") lo mejor.

  1. Tenga en cuenta que, dado que esto se escribió originalmente, MongoDB introdujo el $lookup operador que de hecho realiza "uniones" entre colecciones en el servidor. Para los propósitos de la discusión general aquí, "mejor" en la mayoría de las circunstancias que la sobrecarga de "consultas múltiples" incurrida por populate() y "consultas múltiples" en general, todavía hay una "sobrecarga significativa" incurrido con cualquier $lookup operación.

El principio central del diseño es "incrustado", lo que significa que "ya está allí" en lugar de "obtener de otro lugar". Esencialmente, la diferencia entre "en su bolsillo" y "en el estante", y en términos de E/S generalmente más como "en el estante de la biblioteca del centro" y notablemente más lejos para las solicitudes basadas en la red.