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

Optimización de consultas MongoDB

Lo que desea es un resultado de "búsqueda por facetas" en el que mantenga las estadísticas sobre los términos coincidentes en el conjunto de resultados actual. Posteriormente, si bien hay productos que "parecen" hacer todo el trabajo en una sola respuesta, debe tener en cuenta que la mayoría de los motores de almacenamiento genéricos necesitarán varias operaciones.

Con MongoDB puede usar dos consultas para obtener los resultados y otra para obtener la información de las facetas. Esto daría resultados similares a los resultados facetados disponibles de productos de motores de búsqueda dedicados como Solr o ElasticSearch.

Pero para hacer esto de manera efectiva, desea incluir esto en su documento de manera que pueda usarse de manera efectiva. Una forma muy efectiva de lo que desea es usar una matriz de datos tokenizados:

 {
     "otherData": "something",
     "facets": [
         "country:UK",
         "city:London-UK",
         "genre:Student"
     ]
 }

Entonces, "factets" es un solo campo en su documento y no en múltiples ubicaciones. Esto hace que sea muy fácil de indexar y consultar. Luego, puede agregar efectivamente sus resultados y obtener los totales para cada faceta:

User.aggregate(
    [
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

O más idealmente con algunos criterios en $match :

User.aggregate(
    [
        { "$match": { "facets": { "$in": ["genre:student"] } } },
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

En última instancia, dando una respuesta como:

{ "_id": "country:FR", "count": 50 },
{ "_id": "country:UK", "count": 300 },
{ "_id": "city:London-UK", "count": 150 },
{ "_id": "genre:Student": "count": 500 }

Tal estructura es fácil de atravesar e inspeccionar cosas como el "país" discreto y la "ciudad" que pertenece a un "país", ya que esos datos están separados consistentemente por un guión "-".

Intentar combinar documentos dentro de matrices es una mala idea. También se debe respetar un límite de tamaño de BSON de 16 MB, de los cuales la combinación de resultados (especialmente si está tratando de mantener el contenido del documento) seguramente terminará superándose en la respuesta.

Para algo tan simple como obtener el "recuento general" de resultados de dicha consulta, simplemente resuma los elementos de un tipo de faceta en particular. O simplemente emita sus mismos argumentos de consulta a un .count() operación:

User.count({ "facets": { "$in": ["genre:Student"] } },function(err,count) {

});

Como se dijo aquí, particularmente cuando se implementa la "paginación" de los resultados, las funciones de obtener el "Recuento de resultados", "Recuentos de facetas" y la "Página de resultados" real se delegan en consultas "separadas" al servidor.

No hay nada de malo en enviar cada una de esas consultas al servidor en paralelo y luego combinar una estructura para alimentar su plantilla o aplicación que se parece mucho al resultado de búsqueda facetado de uno de los productos de motor de búsqueda que ofrece este tipo de respuesta.

Conclusión

Así que ponga algo en su documento para marcar las facetas en un solo lugar. Una matriz de cadenas tokenizadas funciona bien para este propósito. También funciona bien con formularios de consulta como $in y $all para las condiciones "o" o "y" en las combinaciones de selección de facetas.

No intente combinar los resultados o anidar las adiciones solo para que coincidan con alguna estructura jerárquica percibida, sino que recorra los resultados recibidos y use patrones simples en los tokens. Es muy simple

Ejecute consultas paginadas para el contenido como consultas separadas para facetas o recuentos generales. Intentar empujar todo el contenido en matrices y luego limitarlo solo para obtener recuentos no tiene sentido. Lo mismo se aplicaría a una solución RDBMS para hacer lo mismo, donde los resultados de paginación cuentan y la página actual son operaciones de consulta separadas.

Hay más información escrita en el blog de MongoDB sobre la búsqueda facetada con MongoDB que también explica algunas otras opciones. También hay artículos sobre la integración con soluciones de búsqueda externas usando mongoconnector u otros enfoques.