MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

MongoDB - Usa il framework di aggregazione o mapreduce per abbinare l'array di stringhe all'interno dei documenti (corrispondenza del profilo)

MapReduce eseguirà JavaScript in un thread separato e utilizzerà il codice fornito per emettere e ridurre parti del documento da aggregare su determinati campi. Puoi certamente considerare l'esercizio come un'aggregazione su ciascun "fieldValue". Anche il framework di aggregazione può eseguire questa operazione, ma sarebbe molto più veloce poiché l'aggregazione verrebbe eseguita sul server in C++ anziché in un thread JavaScript separato. Ma il framework di aggregazione può restituire più dati indietro di 16 MB, nel qual caso dovresti eseguire un partizionamento più complesso del set di dati.

Ma sembra che il problema sia molto più semplice di questo. Vuoi solo trovare per ogni profilo quali altri profili condividono attributi particolari con esso - senza conoscere la dimensione del tuo set di dati e i tuoi requisiti di prestazioni, suppongo che tu abbia un indice su fieldValues ​​quindi sarebbe efficiente eseguire query su di esso e quindi puoi ottenere i risultati desiderati con questo semplice ciclo:

> 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()
       ); 
 }  );

Uscita:

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"
    ]
}
[ ]

Ovviamente puoi modificare la query per non escludere profili già abbinati (modificando {$gt:p._id} a {$ne:{p._id}} e altre modifiche. Ma non sono sicuro di quale valore aggiuntivo otterresti usando il framework di aggregazione o mapreduce poiché questo non sta davvero aggregando una singola raccolta su uno dei suoi campi (a giudicare dal formato dell'output che mostri). Se i requisiti del formato di output sono flessibili, è possibile che tu possa utilizzare anche una delle opzioni di aggregazione integrate.

Ho controllato per vedere come sarebbe se si aggregasse attorno ai singoli fieldValues ​​e non è male, potrebbe aiutarti se il tuo output può corrispondere a questo:

> 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
}

Questo in pratica dice "Per ogni fieldValue ($unwind) raggruppa per fieldValue un array di profili _id e nomi corrispondenti, contando quante corrispondenze accumula ogni fieldValue ($group) e quindi esclude quelli che hanno un solo profilo corrispondente.