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

MongoDB:use el marco de agregación o mapreduce para hacer coincidir la matriz de cadenas dentro de los documentos (coincidencia de perfiles)

MapReduce ejecutaría JavaScript en un hilo separado y usaría el código que proporciona para emitir y reducir partes de su documento para agregar en ciertos campos. Ciertamente puede ver el ejercicio como una agregación sobre cada "fieldValue". El marco de agregación también puede hacer esto, pero sería mucho más rápido ya que la agregación se ejecutaría en el servidor en C++ en lugar de en un subproceso de JavaScript separado. Pero el marco de agregación puede devolver más datos que 16 MB, en cuyo caso deberá realizar una partición más compleja del conjunto de datos.

Pero parece que el problema es mucho más simple que esto. Solo desea encontrar para cada perfil qué otros perfiles comparten atributos particulares con él; sin conocer el tamaño de su conjunto de datos y sus requisitos de rendimiento, supondré que tiene un índice en fieldValues, por lo que sería eficiente consultar en él y luego puede obtener los resultados que desea con este ciclo simple:

> db.profiles.find().forEach( function(p) { 
       print("Matching profiles for "+tojson(p));
       printjson(
            db.profiles.find(
               {"fieldValues": {"$in" : p.fieldValues},  
                                "_id" : {$gt:p._id}}
            ).toArray()
       ); 
 }  );

Salida:

Matching profiles for {
    "_id" : 1,
    "firstName" : "John",
    "lastName" : "Smith",
    "fieldValues" : [
        "favouriteColour|red",
        "food|pizza",
        "food|chinese"
    ]
}
[
    {
        "_id" : 2,
        "firstName" : "Sarah",
        "lastName" : "Jane",
        "fieldValues" : [
            "favouriteColour|blue",
            "food|pizza",
            "food|mexican",
            "pets|yes"
        ]
    },
    {
        "_id" : 3,
        "firstName" : "Rachel",
        "lastName" : "Jones",
        "fieldValues" : [
            "food|pizza"
        ]
    }
]
Matching profiles for {
    "_id" : 2,
    "firstName" : "Sarah",
    "lastName" : "Jane",
    "fieldValues" : [
        "favouriteColour|blue",
        "food|pizza",
        "food|mexican",
        "pets|yes"
    ]
}
[
    {
        "_id" : 3,
        "firstName" : "Rachel",
        "lastName" : "Jones",
        "fieldValues" : [
            "food|pizza"
        ]
    }
]
Matching profiles for {
    "_id" : 3,
    "firstName" : "Rachel",
    "lastName" : "Jones",
    "fieldValues" : [
        "food|pizza"
    ]
}
[ ]

Obviamente, puede modificar la consulta para no excluir los perfiles ya coincidentes (cambiando {$gt:p._id} a {$ne:{p._id}} y otros ajustes. Pero no estoy seguro de qué valor adicional obtendría al usar el marco de agregación o mapreduce, ya que esto no es realmente agregar una sola colección en uno de sus campos (a juzgar por el formato de la salida que muestra). Si sus requisitos de formato de salida son flexibles, ciertamente es posible que también pueda usar una de las opciones de agregación integradas.

Verifiqué para ver cómo se vería esto si se agregara alrededor de valores de campo individuales y no está mal, podría ayudarlo si su salida puede coincidir con esto:

> db.profiles.aggregate({$unwind:"$fieldValues"}, 
      {$group:{_id:"$fieldValues", 
              matchedProfiles : {$push:
               {  id:"$_id", 
                  name:{$concat:["$firstName"," ", "$lastName"]}}},
                  num:{$sum:1}
               }}, 
      {$match:{num:{$gt:1}}});
{
    "result" : [
        {
            "_id" : "food|pizza",
            "matchedProfiles" : [
                {
                    "id" : 1,
                    "name" : "John Smith"
                },
                {
                    "id" : 2,
                    "name" : "Sarah Jane"
                },
                {
                    "id" : 3,
                    "name" : "Rachel Jones"
                }
            ],
            "num" : 3
        }
    ],
    "ok" : 1
}

Esto básicamente dice "Para cada valor de campo ($desenrollar), agrupe por valor de campo una matriz de _ids y nombres de perfil coincidentes, contando cuántas coincidencias acumula cada valor de campo ($grupo) y luego excluya las que solo tienen un perfil coincidente.