2013-06-10 6 views
0

En interrogeant une base de données mongoDB avec map_reduce, j'ai besoin de limiter les résultats réels. J'espérais utiliser l'option query mais cela ne limite que les données de la partie map. Je dois limiter la sortie.MongoDB Mapreduce: requête/restriction/filtre sur le résultat de mapreduce?

Mes données se présente comme suit (de gauche d'autres attributs out):

obj1: { name: "obj1", version: 1, someAttr = "a" }, 
obj1a: { name: "obj1", version: 2, someAttr= "b"}, 

obj2: { name: "obj2", version: 1 }, 
obj2a: { name: "obj2", version: 2} ... 

J'ai des objets qui partagent la même name par version (qui est incrémenté par mise à jour).

Je dois obtenir la nouvelle version de chaque objet, et j'ai carte écrite/réduire les fonctions (il est fait en mongomapper):

MAP:

function() { 
    emit(this.name, this); 
} 

REDUCE:

function(key, values) { 
    var res = values[0]; 
    for(var i=1; i<values.length; i++) 
    { 
    if(values[i].version >res.version) 
    { 
     res = values[i]; 
    } 
    } 
    return res; 
} 

De temps en temps Je dois limiter les résultats et je justifie l'option query pour cela. Cela fonctionne bien, sauf dans un cas d'utilisation:

J'ai besoin de la dernière version de obj1 qui a également someAttr mis à "a".

Alors que j'ai essayé en query est:

name: "obj1", someAttr: "a" 

Le résultat attendu est un résultat vide parce que la dernière version n'a pas someAttr ensemble à "a". Ce que je suis est obj1 avec la version 1 ...

Comment puis-je limiter la sortie uniquement les objets avec someAttr ensemble à "a"?

+0

Avez vous avez envisagé d'utiliser le cadre Agrégation au lieu d'un MapReduce? Vous pouvez utiliser votre requête pour filtrer, puis "$ sort" par version et "$ limit" à un résultat. – WiredPrairie

+0

@WiredPrairie Le framework que j'utilise actuellement est un framework Ruby appelé mongomapper. Il ne prend pas vraiment en charge le cadre d'agrégation. En outre, j'ai besoin d'avoir la version la plus élevée de ** chaque ** objet dans une seule collection, pas seulement le résultat. – MarioDS

+1

Désolé, je ne comprends pas vos données. Le cadre d'agrégation pourrait renvoyer chaque objet (groupé par 'name' par exemple). Vous pouvez utiliser 'MongoMapper.database.command' et passer dans' 'aggregate'' et le pipeline. – WiredPrairie

Répondre

2

Vous pouvez ajouter à votre réduire la fonction

function(key, values) { 
    var res = values[0]; 
    for(var i=1; i<values.length; i++) 
    { 
    if(values[i].version >res.version) 
    { 
     res = values[i]; 
    } 
    } 
    if ('someAttr' in res && res.someAttr == "a") 
    return res; 
} 

Ou si vous voulez vérifier la dernière version entre seulement ceux qui ont someAttr réglé sur « a » que vous pouvez faire

function(key, values) { 
    var res = {version : 0} 
    for(var i=0; i<values.length; i++) 
    { 
    if('someAttr' in res && res.someAttr == "a" && values[i].version >res.version) 
    { 
     res = values[i]; 
    } 
    } 
    return res; 
} 
+0

Vous l'avez pris trop littéralement, il doit être dynamique. Il doit être comme une requête where où je spécifie quel attribut a quelle valeur. Mais map/reduce ne prend pas de paramètres. – MarioDS

+0

La réduction de la carte prend les paramètres dans la portée. Vous pouvez le vérifier [ici] (http: //docs.mongodb.org/manual/reference/method/db.collection.mapReduce/# db.collection.mapReduce) –

+1

Vous venez d'ajouter scope {someAttr: "a"} à votre requête mapreduce (à côté de votre requête, par exemple {query: {...} , scope: {...}) et vous pouvez utiliser le someAttr comme une variable dans votre code javascript mapreduce. –