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

MongoDB - Brug aggregeringsramme eller mapreduce til at matche række af strenge i dokumenter (profilmatching)

MapReduce ville køre JavaScript i en separat tråd og bruge den kode, du giver, til at udsende og reducere dele af dit dokument til at samles på bestemte felter. Du kan bestemt se på øvelsen som en aggregering over hver "fieldValue". Aggregation framework kan også gøre dette, men ville være meget hurtigere, da aggregeringen ville køre på serveren i C++ i stedet for i en separat JavaScript-tråd. Men aggregeringsrammerne kan returnere mere data tilbage end 16 MB, i hvilket tilfælde du bliver nødt til at foretage en mere kompleks partitionering af datasættet.

Men det ser ud til, at problemet er meget enklere end dette. Du vil bare finde for hver profil, hvilke andre profiler der deler bestemte attributter med den - uden at kende størrelsen på dit datasæt og dine præstationskrav, vil jeg antage, at du har et indeks på fieldValues, så det ville være effektivt at forespørge på den, og så kan du få de ønskede resultater med denne simple loop:

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

Output:

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

Du kan naturligvis justere forespørgslen for ikke at udelukke allerede matchede profiler (ved at ændre {$gt:p._id} til {$ne:{p._id}} og andre justeringer. Men jeg er ikke sikker på, hvilken ekstra værdi du ville få ved at bruge aggregeringsramme eller mapreduce, da dette ikke rigtig er at aggregere en enkelt samling på et af dets felter (at dømme efter formatet af det output, du viser). Hvis dine outputformatkrav er fleksible, er det bestemt muligt, at du også kan bruge en af ​​de indbyggede aggregeringsmuligheder.

Jeg tjekkede for at se, hvordan dette ville se ud, hvis det aggregerede omkring individuelle feltværdier, og det er ikke dårligt, det kan måske hjælpe dig, hvis dit output kan matche dette:

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

Dette siger grundlæggende "For hver fieldValue ($unwind) grupper efter fieldValue en række matchende profil _id'er og navne, der tæller hvor mange matches hver fieldValue akkumulerer ($group) og ekskluder derefter dem, der kun har en profil, der matcher den.



  1. Forøg rlimit Mac OSX 10.8

  2. Sådan implementeres MongoDB indlejret $elemMatch Query i C#

  3. Redis forslag til valg af datatype

  4. MongoDB $loft