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

Mongo Ordenar por recuento de coincidencias en matriz

Para responder esto primero, debe "calcular" el número de coincidencias con la condición dada para "ordenar" los resultados y regresar con preferencia a la mayoría de las coincidencias en la parte superior.

Para esto necesita el marco de agregación, que es lo que usa para "cálculo" y "manipulación" de datos en MongoDB:

db.multiArr.aggregate([
  { "$match": { "Keys": { "$in": [ "carrot", "banana" ] } } },
  { "$project": {
    "ID": 1,
    "Keys": 1,
    "order": {
      "$size": {
        "$setIntersection": [ ["carrot", "banana"], "$Keys" ]
      }
    }
  }},
  { "$sort": { "order": -1 } }
])

En un MongoDB anterior a la versión 3, puede hacer la forma más larga:

db.multiArr.aggregate([
  { "$match": { "Keys": { "$in": [ "carrot", "banana" ] } } },
  { "$unwind": "$Keys" },
  { "$group": {
    "_id": "$_id",
    "ID": { "$first": "$ID" },
    "Keys": { "$push": "$Keys" },
    "order": {
      "$sum": {
        { "$cond": [
          { "$or": [
           { "$eq": [ "$Keys", "carrot" ] },
           { "$eq": [ "$Keys", "banana" ] }
         ]},
         1,
         0
        ]}
      }
    }
  }},
  { "$sort": { "order": -1 } }
])

En cualquier caso, la función aquí es hacer coincidir primero los posibles documentos con las condiciones proporcionando una "lista" de argumentos con $in . Una vez que se obtienen los resultados, desea "contar" el número de elementos coincidentes en la matriz en la "lista" de posibles valores proporcionados.

En la forma moderna, $setIntersection El operador compara las dos "listas" que devuelven una nueva matriz que solo contiene los miembros coincidentes "únicos". Como queremos saber cuántas coincidencias hubo, simplemente devolvemos el $size de esa lista.

En versiones anteriores, separas la matriz de documentos con $unwind para realizar operaciones en él, ya que las versiones anteriores carecían de los operadores más nuevos que trabajaban con matrices sin alteración. Luego, el proceso analiza cada valor individualmente y si cualquiera de las expresiones en $or coincide con los valores posibles, entonces el $cond ternario devuelve un valor de 1 al $sum acumulador, de lo contrario 0 . El resultado neto es el mismo "recuento de coincidencias" que se muestra para la versión moderna.

Lo último es simplemente $sort los resultados se basan en el "recuento de coincidencias" que se devolvió, por lo que la mayoría de las coincidencias está en "la parte superior". Este es un "orden descendente" y, por lo tanto, proporciona el -1 para indicar eso.

Anexo sobre $in y arreglos

Está malinterpretando un par de cosas sobre las consultas de MongoDB para empezar. El $in El operador en realidad está destinado a una "lista" de argumentos como este:

{ "Keys": { "$in": [ "carrot", "banana" ] } }

Que es esencialmente la forma abreviada de decir "Coincide con 'zanahoria' o 'banana' en la propiedad 'Keys'" . E incluso podría escribirse en forma larga como esta:

{ "$or": [{ "Keys": "carrot" }, { "Keys": "banana" }] }

Lo que realmente debería llevarlo a si fuera una condición de coincidencia "singular", simplemente proporcione el valor para que coincida con la propiedad:

{ "Keys": "carrot" }

Eso debería cubrir la idea errónea de que usa $in para hacer coincidir una propiedad que es una matriz dentro de un documento. Más bien, el caso "inverso" es el uso previsto donde, en cambio, proporciona una "lista de argumentos" para que coincida con una propiedad dada, ya sea esa propiedad una matriz o solo un valor único.

El motor de consulta de MongoDB no distingue entre un valor único o una matriz de valores en una operación de igualdad o similar.